<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>My software engineering journey</title>
    <subtitle>Documenting a personal journey through software engineering, AI, and programming. This blog features deep dives, practical guides, and recent learnings for both seasoned and aspiring developers.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://carlosvin.github.io/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://carlosvin.github.io"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-03-08T00:00:00+00:00</updated>
    <id>https://carlosvin.github.io/atom.xml</id>
    <entry xml:lang="en">
        <title>Building AI-Promptable Full-Stack Apps: A Reproducible Architecture</title>
        <published>2026-03-08T00:00:00+00:00</published>
        <updated>2026-03-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/building-ai-promptable-fullstack-apps/"/>
        <id>https://carlosvin.github.io/building-ai-promptable-fullstack-apps/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/building-ai-promptable-fullstack-apps/">&lt;p&gt;Every time our team started a new full-stack app, we faced the same problem: rebuild the same architecture from scratch. Authentication, database access, UI shell, AI integration — all the plumbing that has nothing to do with the actual business logic.&lt;&#x2F;p&gt;
&lt;p&gt;It started with internal tools, but we quickly realized the patterns apply to any full-stack web application — whether it&#x27;s a customer-facing product, a dashboard, or a side project. After building several applications this way, we extracted the common patterns into a template. This post explains the architecture and the reasoning behind each decision.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leafy-manatee-16b96c.netlify.app&quot;&gt;Live demo&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt; | &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;tanstack-fullstack-ai-template&quot;&gt;Source code&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;Full-stack web applications share a remarkable amount of infrastructure:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A database-backed API with CRUD operations&lt;&#x2F;li&gt;
&lt;li&gt;Authentication from a JWT in request headers&lt;&#x2F;li&gt;
&lt;li&gt;A component library with dark&#x2F;light mode&lt;&#x2F;li&gt;
&lt;li&gt;Error monitoring and performance tracing&lt;&#x2F;li&gt;
&lt;li&gt;Increasingly, an AI assistant that can query the data&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Yet every project starts from &lt;code&gt;npm init&lt;&#x2F;code&gt; and rebuilds all of this. The code looks similar but is never quite the same, making it hard to maintain patterns across a growing portfolio of applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-stack&quot;&gt;The Stack&lt;&#x2F;h2&gt;
&lt;p&gt;We chose &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;start&quot;&gt;TanStack Start&lt;&#x2F;a&gt; as the foundation — a full-stack React meta-framework that gives us:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Server functions&lt;&#x2F;strong&gt; (&lt;code&gt;createServerFn&lt;&#x2F;code&gt;) that act as type-safe RPC endpoints&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;File-based routing&lt;&#x2F;strong&gt; with TanStack Router&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;SSR&lt;&#x2F;strong&gt; via Nitro, deployable anywhere&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Middleware&lt;&#x2F;strong&gt; that runs on every request, perfect for auth&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For the UI, &lt;a href=&quot;https:&#x2F;&#x2F;mantine.dev&#x2F;&quot;&gt;Mantine&lt;&#x2F;a&gt; gives us 120+ production-ready components, dark&#x2F;light mode out of the box, and a theme system that keeps things consistent without writing custom CSS.&lt;&#x2F;p&gt;
&lt;p&gt;For AI, &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;ai&quot;&gt;TanStack AI&lt;&#x2F;a&gt; provides a unified interface across OpenAI, Anthropic, Gemini, and more — with first-class support for tool calling and streaming.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;architecture-everything-behind-an-interface&quot;&gt;Architecture: Everything Behind an Interface&lt;&#x2F;h2&gt;
&lt;p&gt;The core principle is simple: &lt;strong&gt;every external service is accessed through an interface&lt;&#x2F;strong&gt;. This makes each piece swappable without touching application code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-repository-pattern&quot;&gt;The Repository Pattern&lt;&#x2F;h3&gt;
&lt;p&gt;All data access goes through a &lt;code&gt;ReadRepository&lt;&#x2F;code&gt; + &lt;code&gt;WritableRepository&lt;&#x2F;code&gt; interface:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;export interface ReadRepository {
  getTasks(filter?: TaskFilter): Promise&amp;lt;Task[]&amp;gt;
  getTask(taskId: string): Promise&amp;lt;Task | null&amp;gt;
  getAssignees(): Promise&amp;lt;string[]&amp;gt;
}

export interface WritableRepository {
  createTask(input: TaskInput, createdBy?: string): Promise&amp;lt;Task&amp;gt;
  updateTask(taskId: string, input: Partial&amp;lt;TaskInput&amp;gt;): Promise&amp;lt;Task | null&amp;gt;
  deleteTask(taskId: string): Promise&amp;lt;boolean&amp;gt;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Two implementations ship with the template:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;SeedRepository&lt;&#x2F;strong&gt; — in-memory with sample data. Zero configuration, works instantly.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;MongoRepository&lt;&#x2F;strong&gt; — production MongoDB implementation.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A factory function auto-detects which to use based on whether &lt;code&gt;MONGODB_URI&lt;&#x2F;code&gt; is set. For development, you never need a database.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;auth-via-global-middleware&quot;&gt;Auth via Global Middleware&lt;&#x2F;h3&gt;
&lt;p&gt;TanStack Start supports &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;start&#x2F;latest&#x2F;docs&#x2F;framework&#x2F;react&#x2F;guide&#x2F;middleware&quot;&gt;global middleware&lt;&#x2F;a&gt; — functions that run on every request before any handler executes.&lt;&#x2F;p&gt;
&lt;p&gt;We use this for authentication: the middleware reads the JWT from the configured header, decodes the identity, and when the user is authenticated it loads their profile from the repository. Both are attached to the request context:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;&amp;#x2F;&amp;#x2F; src&amp;#x2F;middleware&amp;#x2F;auth.ts
export const authMiddleware = createMiddleware().server(async ({ next, request }) =&amp;gt; {
  const authHeader = request.headers.get(AUTH_HEADER_NAME)
  const identity = extractIdentityFromJwt(authHeader)
  const user = identity.email ? identity : ANONYMOUS_USER

  let userProfile = null
  if (user.email) {
    userProfile = await getReadRepository().getUserProfile(user.email)
  }

  return next({ context: { user, userProfile } })
})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Registered globally in &lt;code&gt;src&#x2F;start.ts&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;export const startInstance = createStart(() =&amp;gt; ({
  requestMiddleware: [authMiddleware],
}))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Every server function automatically receives &lt;code&gt;context.user&lt;&#x2F;code&gt; and &lt;code&gt;context.userProfile&lt;&#x2F;code&gt; — no manual header extraction. For mutations, we chain a function-level &lt;strong&gt;requireAuthMiddleware&lt;&#x2F;strong&gt; (&lt;code&gt;src&#x2F;middleware&#x2F;requireAuth.ts&lt;&#x2F;code&gt;) so only POST server functions require authentication; read-only queries stay unauthenticated. The handler can then assume &lt;code&gt;context.user&lt;&#x2F;code&gt; is defined. For other cases, use the composable guards &lt;code&gt;requireAuth(context)&lt;&#x2F;code&gt; and &lt;code&gt;requireGroup(context, group)&lt;&#x2F;code&gt; from &lt;code&gt;src&#x2F;utils&#x2F;auth.ts&lt;&#x2F;code&gt;; they throw with 401&#x2F;403 so your handler code stays minimal.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;promptable-by-design&quot;&gt;Promptable by Design&lt;&#x2F;h3&gt;
&lt;p&gt;This is the pattern we are most excited about. AI tools call the &lt;strong&gt;same server functions&lt;&#x2F;strong&gt; that route loaders and event handlers use — a single code path for validation, auth, observability, and data access. Tool handlers are wrapped with &lt;code&gt;withErrorHandling()&lt;&#x2F;code&gt; so that failures return &lt;code&gt;{ error: string, code?: number }&lt;&#x2F;code&gt; instead of crashing the agent loop:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;const getTasksToolDef = toolDefinition({
  name: &amp;#x27;getTasks&amp;#x27;,
  description: &amp;#x27;Get all tasks with optional filters...&amp;#x27;,
  inputSchema: TaskFilterSchema,  &amp;#x2F;&amp;#x2F; Zod schema with .describe()
})

export const getTasksTool = getTasksToolDef.server((args) =&amp;gt;
  withErrorHandling(() =&amp;gt; getTasks({ data: TaskFilterSchema.parse(args) }))
)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because we use Zod schemas with &lt;code&gt;.describe()&lt;&#x2F;code&gt; on every field, the AI model receives rich JSON Schema metadata explaining what each parameter means. The model can then compose tool calls to answer complex queries.&lt;&#x2F;p&gt;
&lt;p&gt;We also expose &lt;strong&gt;create&lt;&#x2F;strong&gt;, &lt;strong&gt;update&lt;&#x2F;strong&gt;, and &lt;strong&gt;delete&lt;&#x2F;strong&gt; as AI tools. Since these call the same server functions used by the UI — which already have &lt;code&gt;requireAuthMiddleware&lt;&#x2F;code&gt; chained in — auth and creator checks happen automatically. A &lt;strong&gt;getCurrentUserContext&lt;&#x2F;strong&gt; tool lets the AI check who is logged in and what they can do. When the user is not allowed, mutation server functions throw with 401 or 403, &lt;code&gt;withErrorHandling()&lt;&#x2F;code&gt; catches this and returns &lt;code&gt;{ error, code }&lt;&#x2F;code&gt;, and the AI explains it in plain language: “You need to log in to create tasks” or “Only the task creator can edit that task.”&lt;&#x2F;p&gt;
&lt;p&gt;The template also uses &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;ai&#x2F;latest&#x2F;docs&#x2F;guides&#x2F;client-tools&quot;&gt;TanStack AI client tools&lt;&#x2F;a&gt; — tools that execute in the browser instead of on the server. &lt;strong&gt;navigate&lt;&#x2F;strong&gt; triggers &lt;code&gt;router.navigate()&lt;&#x2F;code&gt; to open a page, and &lt;strong&gt;invalidateRouter&lt;&#x2F;strong&gt; calls &lt;code&gt;router.invalidate()&lt;&#x2F;code&gt; so the UI refreshes after AI-driven mutations. Their definitions live in &lt;code&gt;tools.ts&lt;&#x2F;code&gt; (shared with the server), but the implementations run in the chat drawer component via &lt;code&gt;@tanstack&#x2F;ai-client&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A chat drawer talks to the backend via &lt;code&gt;POST &#x2F;api&#x2F;chat&lt;&#x2F;code&gt; with Server-Sent Events (SSE) streaming. The client sends browser context plus current location (&lt;code&gt;currentPathname&lt;&#x2F;code&gt;, &lt;code&gt;currentSearch&lt;&#x2F;code&gt;, &lt;code&gt;currentHref&lt;&#x2F;code&gt;), and the server injects this into the system prompt as &lt;code&gt;Current Location&lt;&#x2F;code&gt; context.&lt;&#x2F;p&gt;
&lt;p&gt;We also keep a navigation manifest in sync with the route tree (&lt;code&gt;src&#x2F;services&#x2F;ai&#x2F;navigationManifest.ts&lt;&#x2F;code&gt;) so the model understands URL structure, including dynamic routes like &lt;code&gt;&#x2F;tasks&#x2F;$taskId&lt;&#x2F;code&gt; (concrete URLs: &lt;code&gt;&#x2F;tasks&#x2F;&amp;lt;taskId&amp;gt;&lt;&#x2F;code&gt;). This lets the assistant interpret references such as &quot;this page&quot; and &quot;this task&quot; using the route the user is currently viewing.&lt;&#x2F;p&gt;
&lt;p&gt;Users get a natural language interface to their data — and to create, edit, and delete tasks when permitted — with permission-aware error handling.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;observability-as-a-plugin&quot;&gt;Observability as a Plugin&lt;&#x2F;h3&gt;
&lt;p&gt;Monitoring is important but vendor lock-in is not. We define a minimal interface:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;export interface ObservabilityService {
  startSpan&amp;lt;T&amp;gt;(name: string, fn: () =&amp;gt; Promise&amp;lt;T&amp;gt;): Promise&amp;lt;T&amp;gt;
  setUser(user: { email: string; name: string }): void
  captureError(error: unknown): void
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sentry is the default implementation. If &lt;code&gt;VITE_SENTRY_DSN&lt;&#x2F;code&gt; is not set, a no-op implementation is used — the app works perfectly fine without any observability configured. To switch to Datadog, New Relic, or anything else, implement the three methods.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;data-flow-and-conventions&quot;&gt;Data Flow and Conventions&lt;&#x2F;h3&gt;
&lt;p&gt;A few conventions keep the app predictable. &lt;strong&gt;Loaders-first&lt;&#x2F;strong&gt;: all data is fetched in route loaders, not in &lt;code&gt;useEffect&lt;&#x2F;code&gt; + &lt;code&gt;useState&lt;&#x2F;code&gt;; loaders give you caching, SSR, and parallel fetching for free. &lt;strong&gt;URL-as-state&lt;&#x2F;strong&gt;: filters, tabs, and modal open&#x2F;close live in URL search params so state is shareable, bookmarkable, and survives refresh. &lt;strong&gt;Mutations&lt;&#x2F;strong&gt;: POST server functions chain &lt;code&gt;invalidateMiddleware&lt;&#x2F;code&gt;, so after a mutation the client automatically calls &lt;code&gt;router.invalidate()&lt;&#x2F;code&gt; and refetches; components never invalidate manually. Mutation server functions &lt;strong&gt;throw&lt;&#x2F;strong&gt; on error; route callers wrap with &lt;code&gt;processResponse()&lt;&#x2F;code&gt; for a &lt;code&gt;{ data, error }&lt;&#x2F;code&gt; result, so the UI can show toasts or inline errors without try&#x2F;catch in every handler. &lt;strong&gt;E2E tested&lt;&#x2F;strong&gt;: Playwright tests run the full app against the seed repository, covering routes, filters, CRUD, and auth gating — no database needed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zod-schemas-as-the-single-source-of-truth&quot;&gt;Zod Schemas as the Single Source of Truth&lt;&#x2F;h2&gt;
&lt;p&gt;Every domain type starts as a Zod schema:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;typescript&quot; class=&quot;language-typescript &quot;&gt;&lt;code class=&quot;language-typescript&quot; data-lang=&quot;typescript&quot;&gt;export const TaskSchema = TaskInputSchema.extend({
  id: z.string().describe(&amp;#x27;Unique identifier for the task&amp;#x27;),
  createdAt: z.string().describe(&amp;#x27;ISO 8601 timestamp when created&amp;#x27;),
  updatedAt: z.string().describe(&amp;#x27;ISO 8601 timestamp when last updated&amp;#x27;),
})

export type Task = z.infer&amp;lt;typeof TaskSchema&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This single definition serves four purposes:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;TypeScript types&lt;&#x2F;strong&gt; — inferred via &lt;code&gt;z.infer&amp;lt;&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Server function validation&lt;&#x2F;strong&gt; — passed to &lt;code&gt;.inputValidator(Schema)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AI tool schemas&lt;&#x2F;strong&gt; — converted to JSON Schema automatically&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Documentation&lt;&#x2F;strong&gt; — &lt;code&gt;.describe()&lt;&#x2F;code&gt; metadata is embedded everywhere&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;No more maintaining separate interfaces, validation logic, and documentation that inevitably drift apart.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Why Zod?&lt;&#x2F;strong&gt; &lt;a href=&quot;https:&#x2F;&#x2F;arktype.io&#x2F;&quot;&gt;ArkType&lt;&#x2F;a&gt; is a very good alternative and I personally prefer its syntax; we went with Zod here because it is more widely known. Zod v4 also lets you add extra metadata on fields—formatting hints, units, etc.—which is useful for formatting in the UI and for giving better hints to the AI when it uses your schemas.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;project-structure&quot;&gt;Project structure&lt;&#x2F;h3&gt;
&lt;p&gt;The important pieces live under &lt;code&gt;src&#x2F;&lt;&#x2F;code&gt;: &lt;code&gt;middleware&#x2F;&lt;&#x2F;code&gt; (auth, invalidation), &lt;code&gt;services&#x2F;schemas&#x2F;&lt;&#x2F;code&gt; (Zod as single source of truth), &lt;code&gt;services&#x2F;repository&#x2F;&lt;&#x2F;code&gt; (interface plus seed and Mongo implementations), &lt;code&gt;services&#x2F;api&#x2F;&lt;&#x2F;code&gt; (server functions), &lt;code&gt;services&#x2F;ai&#x2F;&lt;&#x2F;code&gt; (adapter and tool definitions), and &lt;code&gt;routes&#x2F;&lt;&#x2F;code&gt; (file-based pages). The repo README has the full tree.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-started-in-30-seconds&quot;&gt;Getting Started in 30 Seconds&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;carlosvin&amp;#x2F;tanstack-fullstack-ai-template.git
cd tanstack-fullstack-ai-template
pnpm install
pnpm dev
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;install-the-skill-npx-skills&quot;&gt;Install The Skill (npx skills)&lt;&#x2F;h2&gt;
&lt;p&gt;You can install this repository&#x27;s generated Agent Skill directly from GitHub:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;# List skills available in this repository
npx skills add carlosvin&amp;#x2F;tanstack-fullstack-ai-template --list

# Install the TanStack fullstack pattern skill
npx skills add carlosvin&amp;#x2F;tanstack-fullstack-ai-template --skill tanstack-fullstack-pattern

# Optional: install globally (available across projects)
npx skills add carlosvin&amp;#x2F;tanstack-fullstack-ai-template --skill tanstack-fullstack-pattern -g

# Optional: verify installed skills
npx skills list
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can also try the &lt;a href=&quot;https:&#x2F;&#x2F;leafy-manatee-16b96c.netlify.app&quot;&gt;live demo&lt;&#x2F;a&gt; without cloning.&lt;&#x2F;p&gt;
&lt;p&gt;For a new project you can run &lt;code&gt;rm -rf .git &amp;amp;&amp;amp; git init&lt;&#x2F;code&gt; after cloning to start fresh history. Use &lt;code&gt;pnpm build&lt;&#x2F;code&gt;, &lt;code&gt;pnpm test&lt;&#x2F;code&gt;, and &lt;code&gt;pnpm lint&lt;&#x2F;code&gt; (and &lt;code&gt;pnpm format&lt;&#x2F;code&gt;) to validate your fork. To run in production via Docker: &lt;code&gt;docker build -t my-app .&lt;&#x2F;code&gt; then &lt;code&gt;docker run --rm -p 3000:3000 my-app&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The app starts with seed data — a working task management system with dashboard, list views, detail pages, dark&#x2F;light mode, and an AI chat drawer. No database, no API keys, no environment variables needed.&lt;&#x2F;p&gt;
&lt;p&gt;When you&#x27;re ready to add real backends, set the relevant variables. The repo includes an &lt;code&gt;.env.example&lt;&#x2F;code&gt; with full documentation; the main ones are:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Variable&lt;&#x2F;th&gt;&lt;th&gt;Purpose&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;MONGODB_URI&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Use a real database instead of in-memory seed data&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AZURE_OPENAI_API_KEY&lt;&#x2F;code&gt;, &lt;code&gt;AZURE_OPENAI_ENDPOINT&lt;&#x2F;code&gt;, &lt;code&gt;AZURE_OPENAI_DEPLOYMENT&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Enable the AI chat assistant (OpenAI-compatible)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;VITE_SENTRY_DSN&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;Enable error and performance monitoring&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AUTH_HEADER_NAME&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;HTTP header for the JWT (default: &lt;code&gt;Authorization&lt;&#x2F;code&gt;)&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Each capability layers on independently. You can clone and replace the Task domain with your own, use the generated Cursor&#x2F;Windsurf skill for AI-assisted setup, or adopt layers incrementally; the repo README has the details.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;extending-the-template&quot;&gt;Extending the Template&lt;&#x2F;h2&gt;
&lt;p&gt;Adding a new domain entity is a six-step process:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Zod schema&lt;&#x2F;strong&gt; in &lt;code&gt;schemas.ts&lt;&#x2F;code&gt; with &lt;code&gt;.describe()&lt;&#x2F;code&gt; annotations&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Repository methods&lt;&#x2F;strong&gt; in the interface, then implement in seed and MongoDB&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Server functions&lt;&#x2F;strong&gt; wrapping the repository (GET for loaders, POST with &lt;code&gt;invalidateMiddleware&lt;&#x2F;code&gt; for mutations)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;AI tools&lt;&#x2F;strong&gt; that call the server functions (wrapped with &lt;code&gt;withErrorHandling()&lt;&#x2F;code&gt;), plus a &lt;strong&gt;getCurrentUserContext&lt;&#x2F;strong&gt; tool so the AI knows who is logged in and what they can do&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Routes&lt;&#x2F;strong&gt; for the UI pages&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Tests&lt;&#x2F;strong&gt; for the seed repository, new utilities, and E2E flows (Playwright runs against seed data)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Because every layer follows the same pattern, adding a new entity takes minutes, not hours. The database, AI provider, and observability layer are behind interfaces; to swap one, implement the interface and update the factory (e.g. &lt;code&gt;getRepository.ts&lt;&#x2F;code&gt; for the repository, the AI adapter factory, or the observability factory in the repo).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;The goal is not a framework — it&#x27;s a &lt;strong&gt;starting point&lt;&#x2F;strong&gt;. Fork the template, replace the Task domain with your own, and you have a production-ready full-stack application with:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Type-safe server functions&lt;&#x2F;li&gt;
&lt;li&gt;JWT authentication via middleware (mutations use requireAuthMiddleware)&lt;&#x2F;li&gt;
&lt;li&gt;AI-powered data querying and task create&#x2F;edit&#x2F;delete with permission-aware errors (401&#x2F;403)&lt;&#x2F;li&gt;
&lt;li&gt;Dark&#x2F;light mode UI&lt;&#x2F;li&gt;
&lt;li&gt;Swappable database, AI provider, and observability&lt;&#x2F;li&gt;
&lt;li&gt;E2E tests via Playwright against seed data (no database needed)&lt;&#x2F;li&gt;
&lt;li&gt;Docker-ready deployment&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;All with zero configuration for local development.&lt;&#x2F;p&gt;
&lt;p&gt;The template is open source at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;tanstack-fullstack-ai-template&quot;&gt;github.com&#x2F;carlosvin&#x2F;tanstack-fullstack-ai-template&lt;&#x2F;a&gt;. You can try the &lt;a href=&quot;https:&#x2F;&#x2F;leafy-manatee-16b96c.netlify.app&quot;&gt;live demo&lt;&#x2F;a&gt; to see it in action before cloning. We hope it saves you the same weeks of scaffolding it saved us.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;em&gt;Built with TanStack Start, Mantine, TanStack AI, MongoDB, Zod, Sentry, Vitest, Playwright, and Biome.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Isolated Integration Tests with pytest-scenarios</title>
        <published>2026-01-03T00:00:00+00:00</published>
        <updated>2026-01-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/pytest-scenarios-isolated-integration-tests/"/>
        <id>https://carlosvin.github.io/pytest-scenarios-isolated-integration-tests/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/pytest-scenarios-isolated-integration-tests/">&lt;p&gt;Integration tests are essential for catching bugs that unit tests miss—but they come with a notorious problem: &lt;strong&gt;shared state&lt;&#x2F;strong&gt;. When tests share a database, they become flaky, order-dependent, and painful to debug.&lt;&#x2F;p&gt;
&lt;p&gt;What if each test could start with a clean slate, with exactly the data it needs, without manual cleanup or complex fixtures?&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&quot;&gt;&lt;code&gt;pytest-scenarios&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; does.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;Consider testing an e-commerce checkout system. You need to verify that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Active customers can complete orders&lt;&#x2F;li&gt;
&lt;li&gt;Suspended customers are rejected&lt;&#x2F;li&gt;
&lt;li&gt;Out-of-stock items fail gracefully&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Each scenario requires different data. With traditional approaches, you either share fixtures (tests interfere), manually clean up (boilerplate hell), or use transaction rollbacks (complex and misses commit-time bugs).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution-declarative-test-scenarios&quot;&gt;The Solution: Declarative Test Scenarios&lt;&#x2F;h2&gt;
&lt;p&gt;With &lt;code&gt;pytest-scenarios&lt;&#x2F;code&gt;, you declare &lt;em&gt;what state you need&lt;&#x2F;em&gt;, and the plugin handles the rest:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;def test_checkout_rejects_suspended_customer(scenario_builder, db):
    # Arrange: Declare the scenario
    scenario_builder.create({
        &amp;quot;customers&amp;quot;: [{&amp;quot;customer_id&amp;quot;: &amp;quot;user_1&amp;quot;, &amp;quot;status&amp;quot;: &amp;quot;suspended&amp;quot;}],
        &amp;quot;products&amp;quot;: [{&amp;quot;product_id&amp;quot;: &amp;quot;item_1&amp;quot;, &amp;quot;in_stock&amp;quot;: True}],
        &amp;quot;orders&amp;quot;: [{&amp;quot;id&amp;quot;: &amp;quot;order_1&amp;quot;, &amp;quot;customer_id&amp;quot;: &amp;quot;user_1&amp;quot;, ...}],
    })

    # Act: Run your business logic
    checkout = Checkout(db)
    result = checkout.process(order_id=&amp;quot;order_1&amp;quot;)

    # Assert: Verify the outcome
    assert result.success is False
    assert &amp;quot;not active&amp;quot; in result.error
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No manual cleanup. No fixture dependencies. Each test is completely isolated.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;key-concepts&quot;&gt;Key Concepts&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;templates-define-defaults&quot;&gt;Templates Define Defaults&lt;&#x2F;h3&gt;
&lt;p&gt;Define templates with sensible defaults—tests only override what matters:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;# tests&amp;#x2F;templates&amp;#x2F;customers.py
TEMPLATE = {
    &amp;quot;name&amp;quot;: &amp;quot;John Doe&amp;quot;,
    &amp;quot;email&amp;quot;: &amp;quot;john.doe@example.test&amp;quot;,
    &amp;quot;status&amp;quot;: &amp;quot;active&amp;quot;,
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;automatic-cleanup&quot;&gt;Automatic Cleanup&lt;&#x2F;h3&gt;
&lt;p&gt;The plugin clears all managed collections &lt;em&gt;before each test&lt;&#x2F;em&gt;. Even if a test fails, the next test starts fresh.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;real-database-testing&quot;&gt;Real Database Testing&lt;&#x2F;h3&gt;
&lt;p&gt;Tests run against a real MongoDB instance, catching issues that mocks would miss: query errors, index problems, schema mismatches.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;try-it-yourself&quot;&gt;Try It Yourself&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve created a complete runnable example that demonstrates &lt;code&gt;pytest-scenarios&lt;&#x2F;code&gt; with a simple e-commerce checkout system.&lt;&#x2F;p&gt;
&lt;p&gt;👉 &lt;strong&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;tree&#x2F;main&#x2F;examples&quot;&gt;View the example on GitHub&lt;&#x2F;a&gt;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The example includes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;blob&#x2F;main&#x2F;examples&#x2F;src&#x2F;checkout.py&quot;&gt;&lt;code&gt;Checkout&lt;&#x2F;code&gt; class&lt;&#x2F;a&gt; with real business logic&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;blob&#x2F;main&#x2F;examples&#x2F;tests&#x2F;integration&#x2F;test_checkout.py&quot;&gt;Integration tests&lt;&#x2F;a&gt; covering happy paths and edge cases&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;tree&#x2F;main&#x2F;examples&#x2F;tests&#x2F;templates&quot;&gt;Templates&lt;&#x2F;a&gt; for customers, products, and orders&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;quick-start&quot;&gt;Quick Start&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;carlosvin&amp;#x2F;pytest-scenarios.git
cd pytest-scenarios&amp;#x2F;examples
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then follow the instructions in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;blob&#x2F;main&#x2F;examples&#x2F;README.md&quot;&gt;example README&lt;&#x2F;a&gt; to run the tests.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;pip install pytest-scenarios
# or
uv add pytest-scenarios
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Configure in &lt;code&gt;pyproject.toml&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;toml&quot; class=&quot;language-toml &quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;[tool.pytest.ini_options]
db-url = &amp;quot;mongodb:&amp;#x2F;&amp;#x2F;127.0.0.1:27017&amp;quot;
db-name = &amp;quot;my_test_db&amp;quot;
templates-path = &amp;quot;tests&amp;#x2F;templates&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;learn-more&quot;&gt;Learn More&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;📦 &lt;a href=&quot;https:&#x2F;&#x2F;pypi.org&#x2F;project&#x2F;pytest-scenarios&#x2F;&quot;&gt;PyPI Package&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;📁 &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&quot;&gt;GitHub Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;📖 &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;pytest-scenarios&#x2F;tree&#x2F;main&#x2F;examples&quot;&gt;Example Project &amp;amp; README&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;Stop fighting flaky integration tests. Let &lt;code&gt;pytest-scenarios&lt;&#x2F;code&gt; handle the isolation while you focus on what matters: testing your business logic.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>About</title>
        <published>2025-08-15T00:00:00+00:00</published>
        <updated>2025-08-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/about/"/>
        <id>https://carlosvin.github.io/about/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/about/">&lt;h2 id=&quot;about-this-blog&quot;&gt;About this blog&lt;&#x2F;h2&gt;
&lt;p&gt;Welcome to &#x27;My Software Engineering Journey&#x27; &lt;a href=&quot;&#x2F;&quot;&gt;blog&lt;&#x2F;a&gt;, a personal blog where I document my adventures in the world of code. Here, I dive deep into topics I&#x27;m passionate about, especially within software engineering, AI, programming languages, code examples, coding practices, recent learnings and more. From deep dives into performance and efficiency to practical guides on building and deploying applications, my goal is to share what I&#x27;ve learned along the way. Whether you&#x27;re a seasoned developer or just starting out, I hope you&#x27;ll find something valuable and inspiring in &lt;a href=&quot;&#x2F;&quot;&gt;these posts&lt;&#x2F;a&gt;. Join me as I explore the ever-evolving landscape of software engineering, one line of code at a time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;small&gt;Note that there are some old posts, that are kind of legacy, I keep them for reference, one example can be &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;about&#x2F;.&#x2F;choosing-modern-cpp-stack&quot;&gt;Choosing a Modern C++ stack&lt;&#x2F;a&gt;, it was written in 2017, updated on 2020, but I guess today is not modern anymore 😄.&lt;&#x2F;small&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;about-me&quot;&gt;About me&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;before&quot;&gt;Before&lt;&#x2F;h3&gt;
&lt;p&gt;Over the years, I&#x27;ve had the privilege of working with industry in great companies like &lt;a href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;&quot;&gt;Microsoft&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.ebay.com&#x2F;&quot;&gt;eBay&lt;&#x2F;a&gt;, Champ, Santander Global Tech and Spanish Lotteries, where I&#x27;ve led teams, architected solutions, and developed scalable systems that power critical business functions. My expertise spans across languages and frameworks such as &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;&quot;&gt;Go&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&#x2F;&quot;&gt;Java&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;&quot;&gt;React&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&#x2F;&quot;&gt;Python&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;&quot;&gt;TypeScript&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;isocpp.org&#x2F;&quot;&gt;C++&lt;&#x2F;a&gt; and more. I&#x27;ve contributed to projects ranging from e-commerce platforms to real-time trading systems, always with a focus on improving efficiency, reliability, and user experience.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;now&quot;&gt;Now&lt;&#x2F;h3&gt;
&lt;p&gt;Currently, I lead the Sales Apps team at &lt;a href=&quot;https:&#x2F;&#x2F;www.mongodb.com&#x2F;&quot;&gt;MongoDB&lt;&#x2F;a&gt;. Our mission is to boost the productivity of the GTM organization by building innovative software solutions. We leverage the &lt;a href=&quot;https:&#x2F;&#x2F;www.mongodb.com&#x2F;resources&#x2F;basics&#x2F;farm-stack&quot;&gt;FARM stack&lt;&#x2F;a&gt;—&lt;a href=&quot;https:&#x2F;&#x2F;fastapi.tiangolo.com&#x2F;&quot;&gt;FastAPI&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;&quot;&gt;React&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.mongodb.com&#x2F;&quot;&gt;MongoDB&lt;&#x2F;a&gt;, and &lt;a href=&quot;https:&#x2F;&#x2F;nextjs.org&#x2F;&quot;&gt;Next.js&lt;&#x2F;a&gt;—along with &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&quot;&gt;TanStack Router&lt;&#x2F;a&gt;, to create tools that help our sales teams work more efficiently and effectively.&lt;&#x2F;p&gt;
&lt;p&gt;We also created a sister team with the same mission of improving GTM efficiency, but focused on leveraging AI to solve problems.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;contact&quot;&gt;Contact&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;m always open to new opportunities and collaborations. Feel free to reach out if you&#x27;d like to connect!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>TanStack Router: Opinionated Guidelines for Production React Apps</title>
        <published>2025-08-15T00:00:00+00:00</published>
        <updated>2025-08-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/tanstack-router-opinionated-conventions-production-react-apps/"/>
        <id>https://carlosvin.github.io/tanstack-router-opinionated-conventions-production-react-apps/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/tanstack-router-opinionated-conventions-production-react-apps/">&lt;p&gt;This post captures a practical way to implement a React application using TanStack Router. It focuses on maintainability, predictable data flows, and ergonomics for both reading and writing code.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;tanstack-router-prod-app&quot;&gt;🔗 GitHub Repository&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;tanstack-router-prod-app&#x2F;&quot;&gt;🚀 Live Preview&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
The guidelines and recommendations in this guide are based on our real-world experience building a new internal application as the Sales Apps Team at &lt;a href=&quot;https:&#x2F;&#x2F;www.mongodb.com&quot;&gt;MongoDB&lt;&#x2F;a&gt;. They reflect lessons learned and best practices developed throughout that process.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;chosen-tech-stack&quot;&gt;Chosen tech stack&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;typescript&quot;&gt;Typescript&lt;&#x2F;h3&gt;
&lt;p&gt;Faster and safer development: Our goal was to catch bugs as early as possible—ideally at compile time, together with a next level developer experience. This approach not only reduces runtime errors but also makes refactoring and onboarding significantly easier.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
In my experience, well-documented project or team guidelines have an even greater positive impact on onboarding than end-to-end typing alone.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;We can see some examples of next level code assistance enabled by TypeScript in tools like &lt;a href=&quot;https:&#x2F;&#x2F;arktype.io&#x2F;&quot;&gt;Arktype&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;latest&quot;&gt;TanStack Router&lt;&#x2F;a&gt;, or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drwpow&#x2F;openapi-typescript&quot;&gt;openapi-typescript&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;e2e-type-safe-arktype-tanstack-router-openapi-fetch&quot;&gt;E2E type safe: Arktype + TanStack router + openapi-fetch&lt;&#x2F;h3&gt;
&lt;p&gt;Any input to our application will be validated and typed, there are different data inputs that can affect our application state:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Search params&lt;&#x2F;strong&gt;: TanStack Router offers robust, type-safe search param validation out of the box. We use &lt;a href=&quot;https:&#x2F;&#x2F;arktype.io&#x2F;&quot;&gt;Arktype&lt;&#x2F;a&gt; for runtime validation, which integrates seamlessly with TanStack Router—see &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;latest&#x2F;docs&#x2F;framework&#x2F;react&#x2F;guide&#x2F;search-params#arktype&quot;&gt;this concise, powerful example&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;&#x2F;strong&gt;: In this case we generate a typed client from the backend &lt;a href=&quot;https:&#x2F;&#x2F;swagger.io&#x2F;docs&#x2F;specification&#x2F;v3_0&#x2F;about&#x2F;&quot;&gt;OpenAPI spec&lt;&#x2F;a&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;openapi-ts.dev&#x2F;openapi-fetch&#x2F;&quot;&gt;&lt;code&gt;openapi-fetch&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. All backend interactions are handled exclusively through this generated client, ensuring type safety and consistency across the app.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
For teams seeking an extra layer of runtime validation, tools like &lt;a href=&quot;https:&#x2F;&#x2F;arktype.io&#x2F;&quot;&gt;Arktype&lt;&#x2F;a&gt; can be used to validate backend responses. However, in our experience—especially as maintainers of both the backend and frontend—this has proven unnecessary. With well-maintained OpenAPI specs, semantic versioning, and strong type generation, we&#x27;ve yet to encounter bugs caused by a mismatch between expected and actual responses. Unless your backend is managed by a separate team or you frequently encounter contract drift, runtime validation with Arktype is likely not needed in this case.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;testing-vitest-react-testing-library&quot;&gt;Testing: Vitest + React testing library&lt;&#x2F;h3&gt;
&lt;p&gt;Here the choices are quite obvious:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;vitest.dev&#x2F;&quot;&gt;Vitest&lt;&#x2F;a&gt; because it is the go-to testing framework if you are using &lt;a href=&quot;https:&#x2F;&#x2F;vitejs.dev&#x2F;&quot;&gt;Vite&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;testing-library.com&#x2F;docs&#x2F;&quot;&gt;Testing Library&lt;&#x2F;a&gt; for intuitive, user-focused component tests.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;project-guidelines&quot;&gt;Project guidelines&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;use-search-params-to-keep-page-state&quot;&gt;Use search params to keep &lt;strong&gt;page&lt;&#x2F;strong&gt; state&lt;&#x2F;h3&gt;
&lt;p&gt;Favor search params over component state for sharable, restorable URLs. This reduces ad‑hoc &lt;code&gt;useState&lt;&#x2F;code&gt; and makes the page state linkable.&lt;&#x2F;p&gt;
&lt;p&gt;This guideline is one of the easiest and most impactful decisions we have made:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Being able for our users to share exactly the same data via URLs was really important and we get this for free.&lt;&#x2F;li&gt;
&lt;li&gt;If we want to change the page state, we just navigate to change search params:&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;import { createFileRoute } from &amp;#x27;@tanstack&amp;#x2F;react-router&amp;#x27;
import { type } from &amp;#x27;arktype&amp;#x27;

const productSearchSchema = type({
    page: &amp;#x27;number = 1&amp;#x27;,
})

export const Route = createFileRoute(&amp;#x27;&amp;#x2F;shop&amp;#x2F;products&amp;#x2F;&amp;#x27;)({
    validateSearch: productSearchSchema,
    loaderDeps: ({ search: { page } }) =&amp;gt; ({ page }),
    loader: ({ deps: { page } }) =&amp;gt; fetchProducts({ page }),
})

function Products () {
    const navigate = Route.useNavigate()

    function handleChangePage(page: number) {
        &amp;#x2F;&amp;#x2F; here we are just updating the query
        navigate({ search: (prev) =&amp;gt; ({...prev, page})})
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the navigation is performed, the loader will be called again to fetch the products in the new page. If the route was already loaded, then it will use the cached data.&lt;&#x2F;p&gt;
&lt;p&gt;Page state is fully type safe, always accessible, and can be as complex as needed. For example, this URL encodes all state to list products on page 2, 100 per page, sorted by ascending price, searching &quot;water ski&quot;:&lt;br &#x2F;&gt;
&lt;code&gt;&#x2F;shop&#x2F;products?page=2&amp;amp;itemsPerPage=100&amp;amp;sort=asc&amp;amp;query=water ski&amp;amp;sortBy=price&lt;&#x2F;code&gt;&lt;br &#x2F;&gt;
Share this URL and everyone sees the exact same state.&lt;&#x2F;p&gt;
&lt;p&gt;If I want to change the state, will only have to navigate sort by date in descending order:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;-`&amp;#x2F;shop&amp;#x2F;products?page=2&amp;amp;itemsPerPage=100&amp;amp;sort=asc&amp;amp;query=water ski&amp;amp;sortBy=price`  
+`&amp;#x2F;shop&amp;#x2F;products?page=2&amp;amp;itemsPerPage=100&amp;amp;sort=desc&amp;amp;query=water ski&amp;amp;sortBy=date`  
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt;&lt;br &#x2F;&gt;
Component-level state management will still be necessary for UI interactions (e.g., form inputs, toggle states, loading indicators). This guideline specifically applies to maintaining the &lt;strong&gt;current page state&lt;&#x2F;strong&gt;—the data and filters that define what content is displayed and should be shareable via URL.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;interacting-with-the-backend&quot;&gt;Interacting with the backend&lt;&#x2F;h3&gt;
&lt;p&gt;Keep backend calls thin and predictable. Recommended approach:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Generate a typed client from your OpenAPI spec (e.g., with &lt;code&gt;openapi-fetch&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Wrap responses in a small helper that normalizes errors into a single &lt;code&gt;AppError&lt;&#x2F;code&gt; shape your UI can consume.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Example shape returned by &lt;code&gt;processResponse&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;type AppError = {
    title: string
    description?: string
}

type Processed&amp;lt;T&amp;gt; = { data?: T; error?: AppError }

async function getProduct(productId: string) {
    &amp;#x2F;&amp;#x2F; response.data: only present if 2XX response
    &amp;#x2F;&amp;#x2F; response.error: only present if 4XX or 5XX response
    const response = await client.GET(&amp;quot;&amp;#x2F;products&amp;#x2F;{product_id}&amp;quot;, {
        params: {
            path: { product_id: productId },
        },
    })

    &amp;#x2F;&amp;#x2F; Here is where we try to convert the error into an AppError unified interface
    const { data, error } = processResponse({ response, action: `Fetching product ${productId}`})

    return {
        data,
        error
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;data-fetching-loaders&quot;&gt;Data fetching - Loaders&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Leverage &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;latest&#x2F;docs&#x2F;framework&#x2F;react&#x2F;guide&#x2F;data-loading#route-loaders&quot;&gt;route loaders&lt;&#x2F;a&gt; when possible&lt;&#x2F;strong&gt; because they simplify data flows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid most data contexts&#x2F;hooks for reads; when the route renders, data is ready to pass down&lt;&#x2F;li&gt;
&lt;li&gt;Built‑in caching based on declared &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;latest&#x2F;docs&#x2F;framework&#x2F;react&#x2F;guide&#x2F;data-loading#dependency-based-stale-while-revalidate-caching&quot;&gt;dependencies&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;exceptions-in-loaders&quot;&gt;Exceptions in loaders&lt;&#x2F;h4&gt;
&lt;p&gt;Throw in loaders (e.g., &lt;code&gt;AppError&lt;&#x2F;code&gt;) so route error components handle failures consistently. Centralize error typing so UIs can show banners&#x2F;toasts with &lt;code&gt;title&lt;&#x2F;code&gt; and &lt;code&gt;description&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is just convenient, because of &lt;a href=&quot;https:&#x2F;&#x2F;tanstack.com&#x2F;router&#x2F;latest&#x2F;docs&#x2F;framework&#x2F;react&#x2F;guide&#x2F;data-loading#handling-errors-with-routeoptionserrorcomponent&quot;&gt;TanStack Error Components&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Applying this pattern, fetching a product now throws on error for cleaner loader usage:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;
function getProduct(productId: string) {
    &amp;#x2F;&amp;#x2F; ... same code as in the example above, the only change is below

    if (error) {
        throw error
    }
    return data
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;mutations&quot;&gt;Mutations&lt;&#x2F;h3&gt;
&lt;p&gt;Mutation functions are similar to fetchers but generally &lt;strong&gt;should NOT throw exceptions&lt;&#x2F;strong&gt;. They&#x27;re invoked from event handlers, and &lt;strong&gt;throwing loses error type information&lt;&#x2F;strong&gt;. Return a &lt;code&gt;{ data, error }&lt;&#x2F;code&gt; object instead.&lt;&#x2F;p&gt;
&lt;p&gt;🚫 Ideally, we want to avoid having to inspect or discriminate error types at runtime:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;try {
    throw new NotFoundError(&amp;#x27;Not Found&amp;#x27;, 404);
} catch (error: unknown) {
    if (error instanceof NotFoundError) {
        console.log(&amp;#x27;The object was not found&amp;#x27;, error.objectId);
    } else {
        console.log(`Caught something else: ${error}`);
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;✅ Using the mutation in a route component:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ts&quot; class=&quot;language-ts &quot;&gt;&lt;code class=&quot;language-ts&quot; data-lang=&quot;ts&quot;&gt;async function handleDelete(productId: string) {
    const { data, error } = await deleteProduct(productId)
    if (error) {
        &amp;#x2F;&amp;#x2F; The error has a title and description attributes
        pushToast({ variant: &amp;#x27;warning&amp;#x27;, ...error })
    } else {
        pushToast({
            variant: &amp;#x27;success&amp;#x27;,
            title: &amp;#x27;Deleted!&amp;#x27;,
            description: `Product ${productId}`
        })
        &amp;#x2F;&amp;#x2F; Invalidate so the loader re-fetches the page state
        router.invalidate()
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;styling&quot;&gt;Styling&lt;&#x2F;h3&gt;
&lt;p&gt;Use CSS Modules for simplicity. Create &lt;code&gt;Component.module.css&lt;&#x2F;code&gt; next to &lt;code&gt;Component.tsx&lt;&#x2F;code&gt;. Vite handles it out of the box, no extra config needed.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&amp;#x2F;&amp;#x2F; HomeLayout.tsx

import classes from &amp;#x27;.&amp;#x2F;HomeLayout.module.css&amp;#x27;

export default function HomeLayout() {
    return (
        &amp;lt;div className={classes.homeContainer}&amp;gt;
        &amp;lt;h2 className={classes.mainTitle}&amp;gt;Welcome!&amp;lt;&amp;#x2F;h2&amp;gt;
        &amp;lt;&amp;#x2F;div&amp;gt;
    )
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;leverage-nested-routing-to-show-nested-components&quot;&gt;Leverage nested routing to show nested components&lt;&#x2F;h3&gt;
&lt;p&gt;If a nested component isn&#x27;t rendered by default (e.g., a modal), make it a nested route instead of toggling hidden UI state.&lt;&#x2F;p&gt;
&lt;p&gt;Benefits:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Clear separation of concerns; no need to render hidden components&lt;&#x2F;li&gt;
&lt;li&gt;Nested routes can access parent loader data&lt;&#x2F;li&gt;
&lt;li&gt;Lazy loading is straightforward&lt;&#x2F;li&gt;
&lt;li&gt;Recoverable app state via URLs (e.g., &lt;code&gt;&#x2F;products&lt;&#x2F;code&gt; vs &lt;code&gt;&#x2F;products&#x2F;new&lt;&#x2F;code&gt; for opening a modal)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;avoid-calling-a-loader-when-the-parent-already-loaded-the-data&quot;&gt;Avoid calling a loader when the parent already loaded the data&lt;&#x2F;h4&gt;
&lt;p&gt;In nested routes, reuse parent data:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;const { currentUser } = useLoaderData({ from: &amp;#x27;__root__&amp;#x27; })
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;leverage-the-default-router-cache&quot;&gt;Leverage the default router cache&lt;&#x2F;h3&gt;
&lt;p&gt;The built‑in cache works well by default. After a mutation followed by navigation, you may want to &lt;code&gt;router.invalidate()&lt;&#x2F;code&gt; to refetch fresh data.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;improve-performance-by-setting-only-the-needed-loader-deps&quot;&gt;Improve performance by setting only the needed loader deps&lt;&#x2F;h4&gt;
&lt;p&gt;The dependencies are also part of the caching mechanism, and only the selected search params will re-fetch data.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;const productsIndexSchema = type({
    page: &amp;#x27;number = 1&amp;#x27;,
    sort: &amp;#x27;&amp;quot;newest&amp;quot; | &amp;quot;oldest&amp;quot; | &amp;quot;price&amp;quot; = &amp;quot;newest&amp;quot;&amp;#x27;,
    condensedView: &amp;#x27;boolean = false&amp;#x27;,
})

&amp;#x2F;&amp;#x2F; &amp;#x2F;routes&amp;#x2F;products.tsx
export const Route = createFileRoute(&amp;#x27;&amp;#x2F;products&amp;#x27;)({
    validateSearch: productsIndexSchema,
    loaderDeps: ({ search: { page, sort } }) =&amp;gt; ({ page, sort }),
    loader: ({ deps: { page, sort } }) =&amp;gt;
        fetchProducts({
            page,
            sort,
        }),
})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this example, updating the state to display a more condensed view does not trigger a data refetch, since &lt;code&gt;condensedView&lt;&#x2F;code&gt; is not included in the &lt;code&gt;loaderDeps&lt;&#x2F;code&gt;. This means the loader will not re-run when only the view mode changes, optimizing performance by avoiding unnecessary network requests.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;&amp;#x2F;&amp;#x2F; This is not making the loader to re-fetch data, because condensedView is not defined in the loaderDeps
Route.navigate({ search: ({prev}) =&amp;gt; ({...prev, condensedView: true})})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;using-router-history&quot;&gt;Using router history&lt;&#x2F;h3&gt;
&lt;p&gt;Use history navigation when it reflects user intent (e.g., closing a modal):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Simpler than reconstructing &lt;code&gt;navigate&lt;&#x2F;code&gt; calls with params and search state&lt;&#x2F;li&gt;
&lt;li&gt;Preserves cache&#x2F;state more often; if you do need fresh data (e.g., post‑mutation), invalidate&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;project-structure&quot;&gt;Project structure&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assets&lt;&#x2F;code&gt;: public assets&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;components&lt;&#x2F;code&gt;: React components; each usually has its own folder with styles and tests&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;hooks&lt;&#x2F;code&gt;: custom React hooks&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;routes&lt;&#x2F;code&gt;: TanStack Router routes (route tree definitions and pages)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;services&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;api&lt;&#x2F;code&gt;: wrappers around backend interactions; see fetch&#x2F;mutation sections&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;schemas&lt;&#x2F;code&gt;: &lt;code&gt;arktype&lt;&#x2F;code&gt; schema definitions&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Easily creating a golang command line tool</title>
        <published>2021-02-14T00:00:00+00:00</published>
        <updated>2021-02-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/create-cmd-tool-golang/"/>
        <id>https://carlosvin.github.io/create-cmd-tool-golang/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/create-cmd-tool-golang/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;&quot;&gt;Golang&lt;&#x2F;a&gt; is one of the most useful technologies I&#x27;ve recently learned. Golang has pretty nice support for networking, command line, or logging out of the box—you don&#x27;t need any dependency. But there are libraries making developers&#x27; life even easier.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve already talked about &lt;a href=&quot;&#x2F;langs&#x2F;en&#x2F;posts&#x2F;rest-service-go-vs-java&#x2F;&quot;&gt;creating REST service in go&lt;&#x2F;a&gt;, today I&#x27;d like to focus on creating a command line tool.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flags&quot;&gt;Flags&lt;&#x2F;h2&gt;
&lt;p&gt;Command line tool to read number of lines as an input integer parameter (Golang):&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;package main

import (
 &amp;quot;flag&amp;quot;
 &amp;quot;fmt&amp;quot;
)

func main() {
 var nFlag = flag.Int(&amp;quot;lines&amp;quot;, 1234, &amp;quot;number of lines&amp;quot;)
 flag.Parse()
 fmt.Printf(&amp;quot;Lines %d\n&amp;quot;, *nFlag)
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With previous simple code we have already some useful capabilities:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;print-help-menu&quot;&gt;Print help menu&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd --help

&amp;gt; Usage of cmd:
    -lines int
        number of lines (default 1234)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;use-default-value&quot;&gt;Use default value&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd

&amp;gt; Lines 1234
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;pass-a-value-to-the-command-tool&quot;&gt;Pass a value to the command tool&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd --lines=2

&amp;gt; Lines 2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;pass-an-invalid-value&quot;&gt;Pass an invalid value&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd --lines=asdf

&amp;gt; invalid value &amp;quot;asdf&amp;quot; for flag -lines: parse error
Usage of cmd:
    -lines int
        number of lines (default 1234)
exit status 2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For a simple command line tool, in most cases, we will have enough with the default language support. But if we want to bring more features to the combo like reading configuration from environment variables or from files, then a library like the awesome &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;spf13&#x2F;viper&quot;&gt;Viper&lt;&#x2F;a&gt; will come really handy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;viper&quot;&gt;Viper&lt;&#x2F;h2&gt;
&lt;p&gt;Viper is a very powerful and well-documented library widely used in many projects. I will not get into the details of how to use it, because I&#x27;ve created an abstraction to simplify its usage, I named it &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;meta-viper&quot;&gt;Meta-Viper&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;meta-viper&quot;&gt;Meta-Viper&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;meta-viper&quot;&gt;Meta-Viper&lt;&#x2F;a&gt; abstracts you from the details of reading configuration from files, environment, or flags. This extra simplicity comes with a tradeoff: we are missing some flexibility.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see some features with an example.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firstly-create-a-go-modules-project-with-the-meta-viper-dependency&quot;&gt;Firstly, create a go modules project with the meta-viper dependency&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;go mod init example.com&amp;#x2F;meta-viper # Create a go modules project
go get github.com&amp;#x2F;carlosvin&amp;#x2F;meta-viper # Install the meta-viper dependency
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s create a program that is configurable from files, command line params, and environment variables.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;main.go&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;package main

import (
 &amp;quot;log&amp;quot;
 &amp;quot;os&amp;quot;

 config &amp;quot;github.com&amp;#x2F;carlosvin&amp;#x2F;meta-viper&amp;quot;
)

&amp;#x2F;&amp;#x2F; Here is where you define the struct that will hold the configuration values
&amp;#x2F;&amp;#x2F; cfg_name is the parameter name
&amp;#x2F;&amp;#x2F; cfg_desc is the parameter description that will be shown in the command line help
type appConfig struct {
 Host      string `cfg_name:&amp;quot;host&amp;quot; cfg_desc:&amp;quot;Server host&amp;quot;`
 Port      int    `cfg_name:&amp;quot;port&amp;quot; cfg_desc:&amp;quot;Server port&amp;quot;`
 SearchAPI string `cfg_name:&amp;quot;apis.search&amp;quot; cfg_desc:&amp;quot;Search API endpoint&amp;quot;`
}

func main() {
 &amp;#x2F;&amp;#x2F; Instantiate the structure with default values
 cfg := &amp;amp;appConfig{
  Host:      &amp;quot;localhost&amp;quot;,
  Port:      6000,
  SearchAPI: &amp;quot;google&amp;quot;,
 }

 &amp;#x2F;&amp;#x2F; Meta-Viper instance is loading the configuration from wherever is available: files, env, or input params
 _, err := config.New(cfg, os.Args)
 if err != nil {
  panic(err)
 }
 log.Printf(&amp;quot;Loaded Configuration %v...&amp;quot;, cfg)
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s see some examples of how this command line tool is able to load configuration.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;print-usage-help&quot;&gt;Print usage (help)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd --help

Usage of flagsConfig:
    --apis.search string    Search API endpoint (default &amp;quot;google&amp;quot;)
    --config string         Configuration name
    --config-dirs strings   Configuration directories search paths (default [.,config,configs,cfg])
    --host string           Server host (default &amp;quot;localhost&amp;quot;)
    --port int              Server port (default 6000)
pflag: help requested
exit status 2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;run-with-default-values&quot;&gt;Run with default values&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ cmd

2021&amp;#x2F;02&amp;#x2F;15 23:12:48 No configuration name has been specified, so no configuration file will be loaded. Using flags and environment variables.
2021&amp;#x2F;02&amp;#x2F;15 23:12:48 Loaded Configuration &amp;amp;{localhost 6000 google}...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;read-the-port-from-environment-variable-and-host-from-input-param&quot;&gt;Read the port from environment variable and host from input param&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ PORT=9999 cmd --host=myhost

2021&amp;#x2F;02&amp;#x2F;15 23:15:47 No configuration name has been specified, so no configuration file will be loaded. Using flags and environment variables.
2021&amp;#x2F;02&amp;#x2F;15 23:15:47 Loaded Configuration &amp;amp;{myhost 9999 google}...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last example will aggregate all the possible sources of configuration, it will extend the previous one adding configuration from a file. So let&#x27;s create a configuration file:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;the-config.json&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
 &amp;quot;apis&amp;quot;: {
  &amp;quot;search&amp;quot;: &amp;quot;duckduckgo&amp;quot;
 }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;read-configuration-from-the-config-json-file-from-environment-and-from-input-params&quot;&gt;Read configuration from the-config.json file, from environment and from input params&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ PORT=9999 cmd --host=myhost --config=the-config

2021&amp;#x2F;02&amp;#x2F;15 23:22:17 Loaded Configuration &amp;amp;{myhost 9999 duckduckgo}...
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TIP: Here you can find a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;meta-viper&#x2F;tree&#x2F;master&#x2F;examples&#x2F;multi-env&quot;&gt;multi-environment example&lt;&#x2F;a&gt; a little bit more complete.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Parameterized Tests in Cypress</title>
        <published>2021-01-06T00:00:00+00:00</published>
        <updated>2021-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/cypress-parametrized-dynamic-tests/"/>
        <id>https://carlosvin.github.io/cypress-parametrized-dynamic-tests/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/cypress-parametrized-dynamic-tests/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.cypress.io&#x2F;&quot;&gt;Cypress&lt;&#x2F;a&gt; is a testing framework for anything running on a web browser. I am using it to test this site and I&#x27;ve talked before about it in the post &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;posts&#x2F;this-is-sapper&#x2F;en#_testing&quot;&gt;&quot;This is Sapper&quot;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In this post I won&#x27;t explain how to use &lt;a href=&quot;https:&#x2F;&#x2F;www.cypress.io&#x2F;&quot;&gt;Cypress&lt;&#x2F;a&gt;, they have a pretty nice documentation: &lt;a href=&quot;https:&#x2F;&#x2F;docs.cypress.io&#x2F;guides&#x2F;getting-started&#x2F;installing-cypress.html&quot;&gt;Getting started with Cypress&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I will stick to the parameterized tests topic.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Parameterized tests&lt;&#x2F;strong&gt;: Also known as dynamic tests, it is an useful technique where you can specify an input dataset and the test case will be repeated for each element in the dataset.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;explicit-input-data-set&quot;&gt;Explicit input data set&lt;&#x2F;h2&gt;
&lt;p&gt;Since sometimes you can’t run the test for all the possible inputs, you can select a set of meaningful data to test.&lt;&#x2F;p&gt;
&lt;p&gt;Example checking that the relevant pages in the site have valid HTML syntax:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;describe(&amp;#x27;validate pages&amp;#x27;, () =&amp;gt; {
    [ &amp;#x2F;&amp;#x2F; &amp;lt;1&amp;gt;
        &amp;quot;&amp;#x2F;&amp;quot;,
        &amp;quot;&amp;#x2F;categories&amp;quot;,
        &amp;quot;&amp;#x2F;categories&amp;#x2F;sapper&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;creating-custom-maven-plugin-default&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;choosing-modern-cpp-stack&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;cpp-mutex&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;cpp-pragma-pack&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;creating-custom-maven-plugin&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;delete-html-tags-py-django&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;gradle-cpp&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;java-embedded-db-performance-comparison&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;react-typescript-parcel&amp;quot;,
        &amp;quot;&amp;#x2F;posts&amp;#x2F;pwa-lessons-learned-cra&amp;quot;,
    ].forEach((url) =&amp;gt; { &amp;#x2F;&amp;#x2F; &amp;lt;2&amp;gt;
        it(`should be valid HTML ${url}`, () =&amp;gt; { &amp;#x2F;&amp;#x2F; &amp;lt;3&amp;gt;
            cy.visit(url)
            cy.htmlvalidate()
        })
    })
})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&amp;lt;1&amp;gt; List with relevant pages to validate&lt;br &#x2F;&gt;
&amp;lt;2&amp;gt; Iterate over the list of pages&lt;br &#x2F;&gt;
&amp;lt;3&amp;gt; Test case execution for selected page&lt;&#x2F;p&gt;
&lt;h3 id=&quot;test-results&quot;&gt;Test results&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;cypress-parametrized-dynamic-tests&#x2F;.&#x2F;html-validation.png&quot; alt=&quot;Test results&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generated-input-data-set&quot;&gt;Generated input data set&lt;&#x2F;h2&gt;
&lt;p&gt;Instead of explicitly defining a data set, you can generate it, for example, creating a random data set.&lt;&#x2F;p&gt;
&lt;p&gt;Example checking that any generated random number is less than 0:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;javascript&quot; class=&quot;language-javascript &quot;&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;describe(&amp;#x27;random&amp;#x27;, () =&amp;gt; {
    const inputData = Array.from(Array(100)).map(x =&amp;gt; Math.random()) &amp;#x2F;&amp;#x2F; &amp;lt;1&amp;gt;
    inputData.forEach(x =&amp;gt; { &amp;#x2F;&amp;#x2F; &amp;lt;2&amp;gt;
        it(`should be valid ${x}`, () =&amp;gt; { &amp;#x2F;&amp;#x2F; &amp;lt;3&amp;gt;
            expect(x).to.be.lessThan(1)
        })
    })
})
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&amp;lt;1&amp;gt; It generates an array of 100 random numbers&lt;br &#x2F;&gt;
&amp;lt;2&amp;gt; Iterate over the generated array&lt;br &#x2F;&gt;
&amp;lt;3&amp;gt; Test case execution&lt;&#x2F;p&gt;
&lt;h3 id=&quot;test-results-1&quot;&gt;Test results&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;cypress-parametrized-dynamic-tests&#x2F;.&#x2F;random-validation.png&quot; alt=&quot;Test results&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; Please check the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cypress-io&#x2F;cypress-example-recipes&#x2F;tree&#x2F;master&#x2F;examples&#x2F;fundamentals__dynamic-tests&quot;&gt;cypress official examples to learn more about dynamic&#x2F;parameterized testing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Golang over Java for REST services</title>
        <published>2020-11-01T00:00:00+00:00</published>
        <updated>2020-11-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/rest-service-go-vs-java/"/>
        <id>https://carlosvin.github.io/rest-service-go-vs-java/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/rest-service-go-vs-java/">&lt;p&gt;Lately I&#x27;ve been working with two different technology stacks almost in parallel, in both cases we were using them to develop &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; services.&lt;&#x2F;p&gt;
&lt;p&gt;During this time I&#x27;ve come up with some conclusions and opinions I&#x27;d like to share.&lt;&#x2F;p&gt;
&lt;p&gt;A disclaimer, few months ago, I had several years of experience with Java and 0 days of professional experience with Golang.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;actual-project-examples&quot;&gt;Actual project examples&lt;&#x2F;h2&gt;
&lt;p&gt;Few months ago I created &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&quot;&gt;an API to extract and structure COVID-19 data&lt;&#x2F;a&gt; from &lt;a href=&quot;https:&#x2F;&#x2F;www.ecdc.europa.eu&#x2F;en&#x2F;publications-data&#x2F;download-todays-data-geographic-distribution-covid-19-cases-worldwide&quot;&gt;ECDC website&lt;&#x2F;a&gt;. I developed it in &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Few months later I had the luck of work on my first professional project in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; and I decided to create a port of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&quot;&gt;the API to extract COVID-19 data&lt;&#x2F;a&gt; in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt;, just for learning and for fun.&lt;&#x2F;p&gt;
&lt;p&gt;Now we have two REST services, almost functionally identical, but developed in two different tech stacks, so we can easily compare some relevant aspects of both.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;source-code-for-the-2-rest-services-implementations&quot;&gt;Source code for the 2 REST services implementations&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; + &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;&lt;&#x2F;th&gt;&lt;th&gt;&lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; + &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt;&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&lt;&#x2F;a&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: I actually created that &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&quot;&gt;COVID-19 data REST API&lt;&#x2F;a&gt; to be the data source for the &lt;a href=&quot;https:&#x2F;&#x2F;covid-stats-pwa.netlify.app&quot;&gt;COVID19-Stats App&lt;&#x2F;a&gt;, a &lt;a href=&quot;https:&#x2F;&#x2F;web.dev&#x2F;progressive-web-apps&quot;&gt;PWA&lt;&#x2F;a&gt; built with &lt;a href=&quot;https:&#x2F;&#x2F;svelte.dev&quot;&gt;Svelte&lt;&#x2F;a&gt;, but that&#x27;s another topic.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;the-ecosystems&quot;&gt;The Ecosystems&lt;&#x2F;h2&gt;
&lt;p&gt;If you want to create a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; service just in plain Java you will have extra work to do, in Golang a little bit less. That&#x27;s why we use framework, because they&#x27;ve already solved many common problems for us.&lt;&#x2F;p&gt;
&lt;p&gt;For this comparison I am going to use &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt; for &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; for &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt;, but in both languages there are a lot of production ready nice options.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;routing&quot;&gt;Routing&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;go-without-framework&quot;&gt;Go - Without framework&lt;&#x2F;h3&gt;
&lt;p&gt;Go uses the concept of &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; multiplexer or router. You can specify routes using patterns and link those routes to handlers. The router will decide which handler has to execute the request based on the path received.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;router-go-file&quot;&gt;router.go file&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;package main

import (
 &amp;quot;log&amp;quot;
 &amp;quot;net&amp;#x2F;http&amp;quot;
)

func main() {
 router := http.NewServeMux()
 router.Handle(&amp;quot;&amp;#x2F;redirect&amp;quot;, http.RedirectHandler(&amp;quot;https:&amp;#x2F;&amp;#x2F;carlosvin.github.io&amp;#x2F;&amp;quot;, 307))
 router.HandleFunc(&amp;quot;&amp;#x2F;hello&amp;quot;, func(w http.ResponseWriter, r *http.Request) {
  w.Write([]byte(&amp;quot;Hello world!&amp;quot;))
 })
 log.Println(&amp;quot;Listening...&amp;quot;)
 http.ListenAndServe(&amp;quot;:3000&amp;quot;, router)
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Source code is already quite simple, but there might more complex routing use cases.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;go-gin-framework&quot;&gt;Go - Gin Framework&lt;&#x2F;h3&gt;
&lt;p&gt;Happily there are frameworks that help us to keep our base code simple, for example when we need to extract path parameters, which is quite common use case in &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt;s, we can use a routing library, I&#x27;ve used &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gorilla&#x2F;mux&quot;&gt;Gorilla Mux&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; and I liked more &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;full-example&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&#x2F;blob&#x2F;master&#x2F;main.go&quot;&gt;Full example&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;import (
 &amp;quot;github.com&amp;#x2F;carlosvin&amp;#x2F;covid-rest-go&amp;#x2F;handlers&amp;quot;
 &amp;quot;github.com&amp;#x2F;carlosvin&amp;#x2F;covid-rest-go&amp;#x2F;readers&amp;quot;
 &amp;quot;github.com&amp;#x2F;gin-gonic&amp;#x2F;gin&amp;quot;
)

func main() {
 
 &amp;#x2F;&amp;#x2F; ...

 r := gin.Default()
 r.GET(&amp;quot;&amp;#x2F;countries&amp;quot;, router.Countries)
 r.GET(&amp;quot;&amp;#x2F;countries&amp;#x2F;:code&amp;quot;, router.Country)
 r.GET(&amp;quot;&amp;#x2F;countries&amp;#x2F;:code&amp;#x2F;dates&amp;quot;, router.CountryDates)
 r.GET(&amp;quot;&amp;#x2F;countries&amp;#x2F;:code&amp;#x2F;dates&amp;#x2F;:date&amp;quot;, router.CountryDate)
 r.Run()

}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;and-this-is-a-handler-example-the-router-countries-one&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest-go&#x2F;blob&#x2F;master&#x2F;handlers&#x2F;countries.go&quot;&gt;And this is a handler example&lt;&#x2F;a&gt;, the router.Countries one&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;func (r *routerImpl) Countries(c*gin.Context) {
 c.JSON(200, r.countries())
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;java-spring-io&quot;&gt;Java + Spring.io&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt; is based on the concept of Controller, it is implemented using annotations on the class and methods.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;controller-example&quot;&gt;Controller Example&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Validated
@RestController &amp;#x2F;&amp;#x2F; (1)
@RequestMapping(&amp;quot;&amp;#x2F;countries&amp;quot;) &amp;#x2F;&amp;#x2F; (2)
public class CountriesController {
 
 &amp;#x2F;&amp;#x2F; Some source code is not shown, you can find the complete example in the repository 

 @GetMapping(&amp;quot;&amp;#x2F;{country}&amp;#x2F;dates&amp;#x2F;{isoDateStr}&amp;quot;)  &amp;#x2F;&amp;#x2F; (3)
 public DateStatsDto getDateByCountry(@Size(min = 2, max = 2) @PathVariable String country, @Size(min = 10, max = 20) @PathVariable String isoDateStr) throws NotFoundException {
  return new DateStatsDto(service.getDate(country, DateUtils.convert(isoDateStr)));
 }

}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;Declare the class as Controller so it is registered in &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Controller base path definition&lt;&#x2F;li&gt;
&lt;li&gt;Handler definition for a nested path under the main controller path. &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt; makes easy to extract path variables defined in the route, you can directly use them as method arguments.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;validations&quot;&gt;Validations&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;go-gin-framework-validation&quot;&gt;Go - Gin Framework Validation&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; uses an external validation package &lt;a href=&quot;https:&#x2F;&#x2F;godoc.org&#x2F;github.com&#x2F;go-playground&#x2F;validator&quot;&gt;validator&lt;&#x2F;a&gt;, besides that it is fully integrated with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;type User struct {
 Name  string `validate:&amp;quot;required&amp;quot;` &amp;#x2F;&amp;#x2F; (1)
 Email string `validate:&amp;quot;required,email&amp;quot;`
}

err := validate.Struct(user) &amp;#x2F;&amp;#x2F; (2)
validationErrors := err.(validator.ValidationErrors) &amp;#x2F;&amp;#x2F; (3)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;The validation system uses &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; tags, it is not the same as &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; annotations, but in the validation case, it works in pretty same way as annotations.&lt;&#x2F;li&gt;
&lt;li&gt;Executes the validation explicitly&lt;&#x2F;li&gt;
&lt;li&gt;Extracts validation errors&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;java-spring-io-validation&quot;&gt;Java + Spring.io Validation&lt;&#x2F;h3&gt;
&lt;p&gt;You can enable the validation in the controller level, then in the handlers you can also specify the type of validation. Let&#x27;s explain it using the previous example:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;countriescontroller-java-validation-example&quot;&gt;CountriesController.java Validation Example&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Validated &amp;#x2F;&amp;#x2F; (1)
@RestController
@RequestMapping(&amp;quot;&amp;#x2F;countries&amp;quot;)
public class CountriesController {
 
 &amp;#x2F;&amp;#x2F; Some source code is not shown, you can find the complete example in the repository 

 @GetMapping(&amp;quot;&amp;#x2F;{country}&amp;#x2F;dates&amp;#x2F;{isoDateStr}&amp;quot;)
 public DateStatsDto getDateByCountry(
  @Size(min = 2, max = 2) @PathVariable String country, &amp;#x2F;&amp;#x2F; (2)
  @Size(min = 10, max = 20) @PathVariable String isoDateStr) throws NotFoundException {
  return new DateStatsDto(service.getDate(country, DateUtils.convert(isoDateStr)));
 }

}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;Declare the class as Controller so it is registered in &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;@Size&lt;&#x2F;code&gt; validates that the input argument country has 2 characters&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The validation system is more powerful than you can see in this code snippet, for example adding &lt;code&gt;@Valid&lt;&#x2F;code&gt; annotation opens the door to complex types validation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;filtering-and-middleware&quot;&gt;Filtering and Middleware&lt;&#x2F;h3&gt;
&lt;p&gt;Different approaches, pretty much the same end result.&lt;&#x2F;p&gt;
&lt;p&gt;I will elaborate this topic in following days.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dependency-injection-ioc&quot;&gt;Dependency injection &#x2F; IoC&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;spring-ioc&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;core.html#beans-factory-collaborators&quot;&gt;Spring IoC&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;core.html#beans-factory-collaborators&quot;&gt;Spring IoC&lt;&#x2F;a&gt; is the most complete and powerful systems I&#x27;ve ever used for &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inversion_of_control&quot;&gt;IoC&lt;&#x2F;a&gt;, actually, the first time I used Spring professionally was just to deal with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inversion_of_control&quot;&gt;IoC&lt;&#x2F;a&gt;. It supports XML configuration files or &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; annotations, I like annotations more, here a simple example from &lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;core.html#beans-factory-collaborators&quot;&gt;Spring IoC&lt;&#x2F;a&gt; documentation:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;spring-ioc-example&quot;&gt;Spring IoC example&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Repository
public class JpaMovieFinder implements MovieFinder { &amp;#x2F;&amp;#x2F; (1)
    &amp;#x2F;&amp;#x2F; implementation elided for clarity
}

&amp;#x2F;&amp;#x2F;

public class SimpleMovieLister {

    private MovieFinder movieFinder;

    @Autowired &amp;#x2F;&amp;#x2F; (2)
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    &amp;#x2F;&amp;#x2F; ...

}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;JpaMovieFinder&lt;&#x2F;code&gt; is instantiated by &lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;core.html#beans-factory-collaborators&quot;&gt;Spring IoC&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;With &lt;code&gt;@Autowired&lt;&#x2F;code&gt; annotation &lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;core.html#beans-factory-collaborators&quot;&gt;Spring IoC&lt;&#x2F;a&gt; knows that has to inject &lt;code&gt;movieFinder&lt;&#x2F;code&gt; argument. It should be a class implementing &lt;code&gt;MovieFinder&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;go&quot;&gt;Go&lt;&#x2F;h3&gt;
&lt;p&gt;Neither &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; nor &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; has any &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inversion_of_control&quot;&gt;IoC&lt;&#x2F;a&gt; solution, but you can still apply &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dependency_injection&quot;&gt;Dependency Injection&lt;&#x2F;a&gt; technique to decouple your components and improve the testability of your system.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;dependency-injection-simple-example-in-go&quot;&gt;Dependency injection simple example in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go &quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;package main

import &amp;quot;fmt&amp;quot;

&amp;#x2F;&amp;#x2F; Greeter interface to greet the caller
type Greeter interface {
 greet()
}

type greeterHello struct{}

func (g *greeterHello) greet() { &amp;#x2F;&amp;#x2F; (3)
 fmt.Println(&amp;quot;Hello!&amp;quot;)
}

type greeterHi struct{}

func (g *greeterHi) greet() { &amp;#x2F;&amp;#x2F; (4)
 fmt.Println(&amp;quot;Hi!&amp;quot;)
}

&amp;#x2F;&amp;#x2F; App Application representation
type App struct {
 greeters []Greeter &amp;#x2F;&amp;#x2F; (1)
}

func (app *App) startup() {
 for _, v := range app.greeters {
  v.greet()
 }
}

func main() {
 greeters := []Greeter{ &amp;#x2F;&amp;#x2F; (2)
  &amp;amp;greeterHello{},
  &amp;amp;greeterHi{},
  &amp;amp;greeterHello{}}

 app := &amp;amp;App{greeters}

 app.startup()
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;App&lt;&#x2F;code&gt; accepts an array of &lt;code&gt;Greeter&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;During &lt;code&gt;App&lt;&#x2F;code&gt; instantiation we pass different implementations of &lt;code&gt;Greeter&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Greeter implementation that prints &lt;strong&gt;Hello!&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Greeter implementation that prints &lt;strong&gt;Hi!&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;It is more verbose, but there is an advantage, there is nothing hidden, everything is explicit and you have full control of instantiation order.&lt;&#x2F;p&gt;
&lt;p&gt;As soon as you use &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dependency_injection&quot;&gt;Dependency Injection&lt;&#x2F;a&gt;, I don&#x27;t have any strong opinion about using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Inversion_of_control&quot;&gt;IoC&lt;&#x2F;a&gt; system or doing &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dependency_injection&quot;&gt;Dependency Injection&lt;&#x2F;a&gt; manually.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;unit-tests&quot;&gt;Unit tests&lt;&#x2F;h3&gt;
&lt;p&gt;For unit tests there are no big differences.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; comes with a standard &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;testing&#x2F;&quot;&gt;library for testing and benchmarking&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; there are many well-known unit testing frameworks, but Spring already has quite big support for &lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-batch&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;testing.html&quot;&gt;unit testing&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;integration-tests&quot;&gt;Integration tests&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;go-integration-testing&quot;&gt;Go Integration Testing&lt;&#x2F;h4&gt;
&lt;p&gt;There are no support for Integration Tests in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt;, you will have to implement everything by yourself, although it is not difficult, &lt;a href=&quot;https:&#x2F;&#x2F;kpat.io&#x2F;2019&#x2F;06&#x2F;testing-with-gin&#x2F;&quot;&gt;here you can find a simple example&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;spring&quot;&gt;Spring&lt;&#x2F;h4&gt;
&lt;p&gt;On the other hand, &lt;a href=&quot;https:&#x2F;&#x2F;docs.spring.io&#x2F;spring-framework&#x2F;docs&#x2F;current&#x2F;reference&#x2F;html&#x2F;testing.html&quot;&gt;Spring has a great testing support&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To write integration tests for &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; services, &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;testing-web&#x2F;&quot;&gt;MockMvc&lt;&#x2F;a&gt; is really convenient.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve used &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest&#x2F;blob&#x2F;master&#x2F;src&#x2F;test&#x2F;java&#x2F;com&#x2F;carlosvin&#x2F;covid&#x2F;CountriesControllerTest.java&quot;&gt;MockMvc in the covid-rest project&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;mockmvc-code-snippet-from-countriescontrollertest-java&quot;&gt;MockMvc code snippet from &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;covid-rest&#x2F;blob&#x2F;master&#x2F;src&#x2F;test&#x2F;java&#x2F;com&#x2F;carlosvin&#x2F;covid&#x2F;CountriesControllerTest.java&quot;&gt;CountriesControllerTest.java&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Autowired
private MockMvc mockMvc; &amp;#x2F;&amp;#x2F; (1)
 
@Test
void getCountries() throws Exception {
 this.mockMvc.perform(get(&amp;quot;&amp;#x2F;countries&amp;quot;)) &amp;#x2F;&amp;#x2F; (2)
   .andDo(print()).andExpect(status().isOk()) &amp;#x2F;&amp;#x2F; (3)
   .andExpect(jsonPath(&amp;quot;$.*&amp;quot;, hasSize(144)))
   .andExpect(jsonPath(&amp;quot;$.ES.confirmedCases&amp;quot;,comparesEqualTo(9191)))
   .andExpect(jsonPath(&amp;quot;$.ES.deathsNumber&amp;quot;, comparesEqualTo(309)))
   .andExpect(jsonPath(&amp;quot;$.ES.countryCode&amp;quot;, comparesEqualTo(&amp;quot;ES&amp;quot;)))
   .andExpect(jsonPath(&amp;quot;$.ES.countryName&amp;quot;, comparesEqualTo(&amp;quot;Spain&amp;quot;)))
   .andExpect(jsonPath(&amp;quot;$.ES.path&amp;quot;, comparesEqualTo(&amp;quot;&amp;#x2F;countries&amp;#x2F;ES&amp;quot;)))
   .andExpect(jsonPath(&amp;quot;$.VC.countryName&amp;quot;, comparesEqualTo(&amp;quot;Saint Vincent and the Grenadines&amp;quot;)))
   .andDo(document(&amp;quot;countries&amp;#x2F;list&amp;quot;, preprocessResponse(prettyPrint(), new CropPreprocessor())));
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;The Spring test runner injects the MockMvc object.&lt;&#x2F;li&gt;
&lt;li&gt;We use MockMvc to call to the endpoint we have created.&lt;&#x2F;li&gt;
&lt;li&gt;Then we validate the endpoint response: status code and body.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;performance&quot;&gt;Performance&lt;&#x2F;h2&gt;
&lt;p&gt;Besides the languages specific differences, the main difference is the performance. The CPU consumption in &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; is smaller, but about the memory the difference is really significant, &lt;strong&gt;the order of 30 times smaller fingerprint&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;memory&quot;&gt;Memory&lt;&#x2F;h3&gt;
&lt;p&gt;Here I&#x27;ve found a surprising difference, just by checking the memory consumption in my laptop.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; &lt;code&gt;15.6MB&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt; &lt;code&gt;465.9MB&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;rest-service-go-vs-java&#x2F;memory-consumption-go-java.png&quot; alt=&quot;Memory consumption&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;speed&quot;&gt;Speed&lt;&#x2F;h3&gt;
&lt;p&gt;Following the &lt;a href=&quot;https:&#x2F;&#x2F;www.techempower.com&#x2F;benchmarks&#x2F;&quot;&gt;TechEmpower benchmarks&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt; is in 193 position, 9.9%.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt; is in 284 position, 4%.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Following the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;the-benchmarker&#x2F;web-frameworks&quot;&gt;The Benchmarker results&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gin-gonic&#x2F;gin&quot;&gt;Gin framework&lt;&#x2F;a&gt;: position 33.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;: position 68.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;If I were you, I&#x27;d choose &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; if:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If you value the explicit over implicit, keep in mind that there is a cost, you will most likely have to write more lines of code.&lt;&#x2F;li&gt;
&lt;li&gt;If you value the simplicity, &lt;a href=&quot;https:&#x2F;&#x2F;golang.org&quot;&gt;Go&lt;&#x2F;a&gt; has a quite reduced set of keywords, which reduces the learning curve and simplifies the code reviews.&lt;&#x2F;li&gt;
&lt;li&gt;If RAM memory usage is critical for your project, actually I&#x27;d just keep away from &lt;a href=&quot;https:&#x2F;&#x2F;spring.io&#x2F;guides&#x2F;gs&#x2F;rest-service&quot;&gt;Spring Boot (REST)&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;If the project you are going to work on is a distributed system, specially if it is based on &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Create a PWA with Create React App: Lessons Learned</title>
        <published>2019-11-04T00:00:00+00:00</published>
        <updated>2020-06-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/pwa-lessons-learned-cra/"/>
        <id>https://carlosvin.github.io/pwa-lessons-learned-cra/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/pwa-lessons-learned-cra/">&lt;p&gt;I started working with &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&quot;&gt;React&lt;&#x2F;a&gt; few year ago, always the project creation was from scratch, not using any template&#x2F;scaffolding. Regarding bundlers normally I used either &lt;a href=&quot;https:&#x2F;&#x2F;webpack.js.org&quot;&gt;Webpack&lt;&#x2F;a&gt; at work or &lt;a href=&quot;https:&#x2F;&#x2F;parceljs.org&quot;&gt;Parcel&lt;&#x2F;a&gt; for personal projects.&lt;&#x2F;p&gt;
&lt;p&gt;Few months ago, I wanted to start a personal project to keep track of my travel expenses. I was in a kind of rush because at that time, I was almost in the middle of my gap year, I wanted to focus on implementing main functionality and get an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Minimum_viable_product&quot;&gt;MVP&lt;&#x2F;a&gt; (minimum viable product) the sooner the better, so I thought it was the right time to try out &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;Create React App&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt; allows you to have a production ready &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt; in &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&quot;&gt;React&lt;&#x2F;a&gt; quickly, which is awesome. They take care of configuration and package dependencies, you only have to take care of dependencies you need for your project and of course, implement your project, &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt; is good, but is not magic.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;As I said, I wanted to be implementing business logic ASAP, so together with using &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;, I also took other decisions&#x2F;shortcuts driven by the need of speeding up the development pace, I will talk about those choices in following sections describing some drawbacks and benefits.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chosen-technology-stack-for-budget-tracker&quot;&gt;Chosen Technology Stack for &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&quot;&gt;React&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&quot;&gt;Typescript&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;del&gt;&lt;a href=&quot;https:&#x2F;&#x2F;formidable.com&#x2F;open-source&#x2F;victory&quot;&gt;Victory&lt;&#x2F;a&gt;&lt;&#x2F;del&gt; &lt;a href=&quot;https:&#x2F;&#x2F;frappe.io&#x2F;charts&quot;&gt;Frappe charts&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;auth&quot;&gt;Firebase Authentication&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;So far I am quite happy with the outcome, but with the lessons learned while developing this app, &lt;strong&gt;in the future, with enough time, most likely I will not choose same technology stack again&lt;&#x2F;strong&gt;. You can try the application &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; and judge for yourself.&lt;&#x2F;p&gt;
&lt;p&gt;Along this post I will describe what are, in my experience, the benefits and drawbacks of taking these shortcuts and technical decisions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;create-react-application-cra&quot;&gt;Create React Application: &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;Create React App&lt;&#x2F;a&gt; doesn’t support &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers_API&#x2F;Using_web_workers&quot;&gt;Web Workers&lt;&#x2F;a&gt; neither allows to customize &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;fundamentals&#x2F;primers&#x2F;service-workers&quot;&gt;Service Worker&lt;&#x2F;a&gt; implementation without &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;49737652&#x2F;what-does-eject-do-in-create-react-app&quot;&gt;ejecting&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;service-worker&quot;&gt;Service worker&lt;&#x2F;h3&gt;
&lt;p&gt;You might want to customize your &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;fundamentals&#x2F;primers&#x2F;service-workers&quot;&gt;Service Worker&lt;&#x2F;a&gt; to send&#x2F;receive &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Client&#x2F;postMessage&quot;&gt;post messages&lt;&#x2F;a&gt;, to perform &lt;a href=&quot;https:&#x2F;&#x2F;wicg.github.io&#x2F;BackgroundSync&#x2F;spec&#x2F;&quot;&gt;background sync&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en&#x2F;docs&#x2F;Web&#x2F;API&#x2F;notification&quot;&gt;show web notifications&lt;&#x2F;a&gt;. In that case, you will have to &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;49737652&#x2F;what-does-eject-do-in-create-react-app&quot;&gt;eject your project&lt;&#x2F;a&gt; and maintain the configuration by yourself, which might imply a little bit of headache.&lt;&#x2F;p&gt;
&lt;p&gt;There are &lt;a href=&quot;https:&#x2F;&#x2F;www.freecodecamp.org&#x2F;news&#x2F;how-to-customize-service-workers-with-create-react-app-4424dda6210c&#x2F;&quot;&gt;other options to customize service worker and avoid ejecting CRA&lt;&#x2F;a&gt;, but they are not straightforward enough for my taste.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;web-worker&quot;&gt;Web worker&lt;&#x2F;h3&gt;
&lt;p&gt;If you need to perform any heavy processing without blocking the main thread, you can just use a &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers_API&#x2F;Using_web_workers&quot;&gt;Web Workers&lt;&#x2F;a&gt;, but this feature is not supported by &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;. The &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers_API&#x2F;Using_web_workers&quot;&gt;Web Workers&lt;&#x2F;a&gt; can communicate with main thread using &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Client&#x2F;postMessage&quot;&gt;post messages&lt;&#x2F;a&gt; and it can also show &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;young-coder&#x2F;a-simple-introduction-to-web-workers-in-javascript-b3504f9d9d1c&quot;&gt;web push notifications&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There are also &lt;a href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@danilog1905&#x2F;how-to-use-web-workers-with-react-create-app-and-not-ejecting-in-the-attempt-3718d2a1166b&quot;&gt;other options to use Web Workers in CRA and not eject&lt;&#x2F;a&gt;, but they imply quite some extra work.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;webpack&quot;&gt;Webpack&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;webpack.js.org&quot;&gt;Webpack&lt;&#x2F;a&gt; is the bundler used by &lt;a href=&quot;https:&#x2F;&#x2F;create-react-app.dev&quot;&gt;CRA&lt;&#x2F;a&gt;. You don’t need to know much about it, unless you &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;49737652&#x2F;what-does-eject-do-in-create-react-app&quot;&gt;eject your project&lt;&#x2F;a&gt;, then you will have to deal with &lt;a href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;configuration&#x2F;&quot;&gt;Webpack configuration file&lt;&#x2F;a&gt;, this is just a warning, just in case you are not comfortable with it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;firebase&quot;&gt;Firebase&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; supports data synchronization between different devices, so it requires a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Front_and_back_ends&quot;&gt;backend&lt;&#x2F;a&gt; side to deal with authentication and to save&#x2F;read data remotely. I considered two options: &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; or implement &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; API.&lt;&#x2F;p&gt;
&lt;p&gt;For this &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Front_and_back_ends&quot;&gt;backend&lt;&#x2F;a&gt;, I chose &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; because it is super easy to implement, because there is nothing to implement. You only have to configure &lt;a href=&quot;https:&#x2F;&#x2F;support.google.com&#x2F;firebase&#x2F;answer&#x2F;6400716?hl=en&quot;&gt;authentication methods&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&#x2F;security&#x2F;get-started&quot;&gt;security rules&lt;&#x2F;a&gt; for &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;But &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; brings some drawbacks you must know before choosing it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;bundle-size&quot;&gt;Bundle size&lt;&#x2F;h4&gt;
&lt;p&gt;I got really shocked first time I analyzed &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; bundle size after integrating it with &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt;, &lt;strong&gt;it grew around a 39%!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;27% from &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; library.&lt;&#x2F;li&gt;
&lt;li&gt;12% from &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;auth&quot;&gt;Firebase Authentication&lt;&#x2F;a&gt; library.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Happily &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; implementation is following &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&#x2F;docs&#x2F;code-splitting.html&quot;&gt;code-splitting&lt;&#x2F;a&gt; principle, so user experience was not really affected with this integration. But user’s device will eventually have to download this extra 39% (&lt;strong&gt;539KB&lt;&#x2F;strong&gt;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;offline-first-not-really&quot;&gt;Offline first, not really&lt;&#x2F;h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important&lt;&#x2F;strong&gt;: This section is not relevant if your use case doesn’t imply saving data linked to the user.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; requires user to be authenticated, but &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;auth&#x2F;web&#x2F;anonymous-auth&quot;&gt;user can be anonymous&lt;&#x2F;a&gt;, this is really cool feature if you don’t want to force the user to identify to use the app.&lt;&#x2F;p&gt;
&lt;p&gt;Another very useful and cool &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; feature is that &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&#x2F;manage-data&#x2F;enable-offline&quot;&gt;it supports offline mode&lt;&#x2F;a&gt;, so data can be saved and read even there is no Internet connection.&lt;&#x2F;p&gt;
&lt;p&gt;Anonymous user + offline mode features will allow an application to work as offline first.&lt;&#x2F;p&gt;
&lt;p&gt;So… what is this &lt;em&gt;Offline first, not really&lt;&#x2F;em&gt; issue about? Let me explain a tricky scenario. First time the application is opened, &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; needs to authenticate the user, to do so, user’s device has to be connected to Internet, so &lt;strong&gt;you have to consider following scenario&lt;&#x2F;strong&gt; and either be OK with it or deal with it:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt; is installed in your device.&lt;&#x2F;li&gt;
&lt;li&gt;User is not authenticated.&lt;&#x2F;li&gt;
&lt;li&gt;User’s device is offline.&lt;&#x2F;li&gt;
&lt;li&gt;User opens the &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt; and tries to save some data.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;That data won’t be saved correctly&lt;&#x2F;strong&gt;, because there is no user to link the data with, not even an anonymous user, because application needs to call &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; API to create an anonymous user.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This is not big deal, because it will seldom occur. If you want to deal with it anyway, check next section explaining how and why I did deal with this scenario.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;how-did-i-deal-with-this-issue-with-budget-tracker&quot;&gt;How did I deal with this issue with Budget Tracker?&lt;&#x2F;h5&gt;
&lt;p&gt;First of all, this &lt;strong&gt;might not be an issue for your use case&lt;&#x2F;strong&gt;, because it will happen only first time application is loaded. I just wanted &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; to be fully offline first, because it brings other benefits.&lt;&#x2F;p&gt;
&lt;h6 id=&quot;implementation-details&quot;&gt;Implementation details&lt;&#x2F;h6&gt;
&lt;ul&gt;
&lt;li&gt;Implement 2 persistence layers: Local (&lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;IndexedDB_API&quot;&gt;IndexedDB&lt;&#x2F;a&gt;) and Remote (&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;Save always data locally, regardless user authentication status.&lt;&#x2F;li&gt;
&lt;li&gt;If there is any authenticated user, after saving to local layer, propagate same action to remote layer (&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt;) asynchronously.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h6 id=&quot;benefits&quot;&gt;Benefits&lt;&#x2F;h6&gt;
&lt;ul&gt;
&lt;li&gt;If user is not authenticated, &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; won’t load &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; client bundle. As I explained before, it is 27% of application size.&lt;&#x2F;li&gt;
&lt;li&gt;Application reads and writes are faster, because latest valid data is always saved locally.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clarification&lt;&#x2F;strong&gt;: Save data in &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; is also fast, because data is also cached locally, but it does a little bit more than just saving to &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;IndexedDB_API&quot;&gt;IndexedDB&lt;&#x2F;a&gt; and you need an authenticated user.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can find a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;budget-tracker&#x2F;blob&#x2F;master&#x2F;doc&#x2F;preformance.md#desktop-slow-clear-storage-0-budgets-1&quot;&gt;more detailed performance report&lt;&#x2F;a&gt;, where I analyze 3 different implementations:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Only &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; client.&lt;&#x2F;li&gt;
&lt;li&gt;Local (&lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;IndexedDB_API&quot;&gt;IndexedDB&lt;&#x2F;a&gt;) and remote (&lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt;) persistence layers.&lt;&#x2F;li&gt;
&lt;li&gt;Same as previous one, but remote layer implemented in service worker.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The performance results were in general better for option 2.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;data-model&quot;&gt;Data model&lt;&#x2F;h4&gt;
&lt;p&gt;Firestore API is easy and intuitive, I really like it, but don’t assume it will have same features as other document DBs or SQL DBs.&lt;&#x2F;p&gt;
&lt;p&gt;Check if &lt;a href=&quot;https:&#x2F;&#x2F;googleapis.github.io&#x2F;google-cloud-dotnet&#x2F;docs&#x2F;Google.Cloud.Firestore&#x2F;datamodel.html&quot;&gt;Firestore limitations&lt;&#x2F;a&gt; fit into your data model, or if it is not too late, define your data model following &lt;a href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;firestore&#x2F;docs&#x2F;best-practices&quot;&gt;Firestore best practices&lt;&#x2F;a&gt; and having those limitations in mind.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;firebase-alternatives&quot;&gt;Firebase alternatives&lt;&#x2F;h3&gt;
&lt;p&gt;Besides implementing a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; API, there are other services similar to &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;&quot;&gt;Firebase&lt;&#x2F;a&gt; with smaller client bundle size and other features which might fit better to your requirements.&lt;&#x2F;p&gt;
&lt;p&gt;Consider other alternatives:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Based on &lt;a href=&quot;http:&#x2F;&#x2F;couchdb.apache.org&#x2F;&quot;&gt;Apache CouchDB&lt;&#x2F;a&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;pouchdb.com&quot;&gt;PouchDB&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cloudant&quot;&gt;Cloudant&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Based on &lt;a href=&quot;https:&#x2F;&#x2F;parseplatform.org&#x2F;&quot;&gt;Parse server&lt;&#x2F;a&gt;: &lt;a href=&quot;https:&#x2F;&#x2F;www.back4app.com&quot;&gt;back4apps&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ui-components-library-material-ui&quot;&gt;UI Components Library: &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I chose &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;, from their web&lt;&#x2F;p&gt;
&lt;p&gt;React components for faster and easier web development. Build your own design system, or start with Material Design.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;There were two reasons which drove me to use &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;To create simple UI components which are accessible, &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&#x2F;guides&#x2F;responsive-ui&#x2F;#responsive-ui&quot;&gt;responsive&lt;&#x2F;a&gt; and with a consistent design is tricky and time consuming.&lt;&#x2F;li&gt;
&lt;li&gt;It has SVG set of &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&#x2F;components&#x2F;material-icons&#x2F;&quot;&gt;Material Icons&lt;&#x2F;a&gt;. &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; allows to create categories defined by a name and a selectable icon, so this icon set was really convenient.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There are some &lt;strong&gt;drawbacks&lt;&#x2F;strong&gt;, not very important in my opinion, maybe the most annoying for me is the first one:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;jestjs.io&#x2F;docs&#x2F;en&#x2F;snapshot-testing&quot;&gt;Jest Snapshots&lt;&#x2F;a&gt; + &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt;: The snapshots are generated with &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&quot;&gt;Material UI&lt;&#x2F;a&gt; CSS class names, but CSS classes order might not be deterministic, so a test might pass in your local host but not in &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Continuous_integration&quot;&gt;CI&lt;&#x2F;a&gt; host. They are working on solve &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mui-org&#x2F;material-ui&#x2F;issues&#x2F;14357&quot;&gt;this issue, more info at github&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Performance: There are some performance &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;mui-org&#x2F;material-ui&#x2F;issues?utf8=%E2%9C%93&amp;amp;q=is%3Aissue+is%3Aopen+performance&quot;&gt;issues in Github&lt;&#x2F;a&gt;. During last months, whilst I’ve been using this library, I can say they are working hard on fix them and bring new features.&lt;&#x2F;li&gt;
&lt;li&gt;UI components libraries are complex and do quite a lot work, so most of them are quite heavy. &lt;a href=&quot;https:&#x2F;&#x2F;bundlephobia.com&#x2F;result?p=@material-ui&#x2F;core@4.5.2&quot;&gt;Material UI bundle size weights: 304.2kB minified&lt;&#x2F;a&gt;. You can find some &lt;a href=&quot;https:&#x2F;&#x2F;material-ui.com&#x2F;guides&#x2F;minimizing-bundle-size&quot;&gt;recommendations to reduce bundle size at Material UI website&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;charts-library&quot;&gt;Charts library&lt;&#x2F;h2&gt;
&lt;p&gt;Many of the chart libraries I’ve found are really powerful and complete, but they are also heavy because they depend on other third party libraries like &lt;a href=&quot;https:&#x2F;&#x2F;d3js.org&#x2F;&quot;&gt;D3&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Initially I chose &lt;a href=&quot;https:&#x2F;&#x2F;formidable.com&#x2F;open-source&#x2F;victory&quot;&gt;Victory&lt;&#x2F;a&gt;, but I realized that I only needed charts to show percentages and time series and &lt;a href=&quot;https:&#x2F;&#x2F;formidable.com&#x2F;open-source&#x2F;victory&quot;&gt;Victory&lt;&#x2F;a&gt;’s &lt;a href=&quot;https:&#x2F;&#x2F;bundlephobia.com&#x2F;result?p=victory@33.1.2&quot;&gt;bundle size is 468KB minified&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After quick search in the Internet I discovered other lighter alternatives:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;frappe.io&#x2F;charts&quot;&gt;Frappe charts&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;bundlephobia.com&#x2F;result?p=frappe-charts@1.3.0&quot;&gt;63KB minified&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;gionkunz.github.io&#x2F;chartist-js&quot;&gt;Chartist&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;bundlephobia.com&#x2F;result?p=chartist@0.11.4&quot;&gt;39KB minified&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I tried them and I liked both. I chose &lt;a href=&quot;https:&#x2F;&#x2F;frappe.io&#x2F;charts&quot;&gt;Frappe charts&lt;&#x2F;a&gt; because I thought its default color scheme fits better with &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt; theme.&lt;&#x2F;p&gt;
&lt;p&gt;Both libraries come with more chart types than just bars and XY axis, take a quick look at their websites if you are interested about their supported chart set and to check how they look like.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I will try to come up with a conclusion better than: &lt;em&gt;&quot;It depends&quot;&lt;&#x2F;em&gt;, &lt;em&gt;&quot;Your use case will tell you&quot;&lt;&#x2F;em&gt; and so on.&lt;&#x2F;p&gt;
&lt;p&gt;That said. It depends on your needs :p.&lt;&#x2F;p&gt;
&lt;p&gt;Seriously, let’s play &lt;em&gt;&quot;do not go for … if …&quot;&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-not-go-for-cra-if&quot;&gt;Do not go for CRA if&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;You want to customize &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;fundamentals&#x2F;primers&#x2F;service-workers&quot;&gt;Service Worker&lt;&#x2F;a&gt; for &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;updates&#x2F;2015&#x2F;12&#x2F;background-sync&quot;&gt;Background sync&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en&#x2F;docs&#x2F;Web&#x2F;API&#x2F;notification&quot;&gt;showing push notifications&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;You want to use &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;Web_Workers_API&#x2F;Using_web_workers&quot;&gt;Web Workers&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;do-not-go-for-firestore-if&quot;&gt;Do not go for Firestore if&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;You are aiming for your app to be hit by many users and you don’t know the estimated amount of reads&#x2F;writes, otherwise you might get surprised with the bill. &lt;a href=&quot;https:&#x2F;&#x2F;firebase.google.com&#x2F;docs&#x2F;firestore&quot;&gt;Firestore&lt;&#x2F;a&gt; scales like charm, maybe your budget doesn’t.&lt;&#x2F;li&gt;
&lt;li&gt;Bundle size is critical for your web application. Remember that bundle size is not that critical if you are implementing a &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt;, because your app files are cached.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;do-not-go-blindly-for-the-best-charting-library&quot;&gt;Do not go blindly for the best charting library&lt;&#x2F;h3&gt;
&lt;p&gt;First of all, check what kind of charts you need. In many applications you are OK with XY axis chart, time series, bars or pie charts. You can easily get an smaller bundle size by just using a simple charting library like &lt;a href=&quot;https:&#x2F;&#x2F;frappe.io&#x2F;charts&quot;&gt;Frappe charts&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;gionkunz.github.io&#x2F;chartist-js&quot;&gt;Chartist&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;&#x2F;strong&gt;: Just check what are your requirements, if you are not sure about them, [Chosen Technology Stack for &lt;a href=&quot;https:&#x2F;&#x2F;btapp.netlify.com&quot;&gt;Budget Tracker&lt;&#x2F;a&gt;](#chosen-technology-stack-for-budget-tracker) consists of awesome products which most likely will fit your use case.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;what-next&quot;&gt;What next?&lt;&#x2F;h2&gt;
&lt;p&gt;My next technology stack bet goes for &lt;a href=&quot;https:&#x2F;&#x2F;svelte.dev&quot;&gt;Svelte&lt;&#x2F;a&gt;&#x2F;&lt;a href=&quot;https:&#x2F;&#x2F;sapper.svelte.dev&quot;&gt;Sapper&lt;&#x2F;a&gt;, it is promising project, the results for small projects are really impressive, mainly in regards to bundle size, it is ridiculously small and development experience is quick and intuitive.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve created a tiny &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt; to estimate &lt;a href=&quot;https:&#x2F;&#x2F;currency-loss.netlify.com&quot;&gt;currency exchange loss&lt;&#x2F;a&gt; when you go to a money changer shop: &lt;a href=&quot;https:&#x2F;&#x2F;currency-loss.netlify.com&quot;&gt;currency-loss.netlify.com&lt;&#x2F;a&gt;. Note, I got that app up and running in few hours, thanks to &lt;a href=&quot;https:&#x2F;&#x2F;svelte.dev&quot;&gt;Svelte&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Create SPA with React + Typescript + Parcel</title>
        <published>2019-01-01T00:00:00+00:00</published>
        <updated>2019-07-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/react-typescript-parcel/"/>
        <id>https://carlosvin.github.io/react-typescript-parcel/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/react-typescript-parcel/">&lt;p&gt;I was about to start yet another personal project, it consists of a SPA (Single Page Application) for a travel journal.&lt;&#x2F;p&gt;
&lt;p&gt;Some time ago I tried &lt;a href=&quot;https:&#x2F;&#x2F;parceljs.org&quot;&gt;Parcel&lt;&#x2F;a&gt;, I really loved how simple it was to create a simple project from scratch, using &lt;a href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;&quot;&gt;Typescript&lt;&#x2F;a&gt; + &lt;a href=&quot;https:&#x2F;&#x2F;reactjs.org&quot;&gt;React&lt;&#x2F;a&gt; stack. I’ve decided to create this template or base project, so next time I want to create a new SPA with my favorite frontend stack, I will only have to:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;carlosvin&amp;#x2F;react-typescript-parcel-template.git
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;read-this-before-parcel-is-not-as-mature-as-webpack&quot;&gt;Read this before: Parcel is not as mature as Webpack&lt;&#x2F;h2&gt;
&lt;p&gt;If you want to create a production ready React application, use &lt;a href=&quot;https:&#x2F;&#x2F;webpack.js.org&#x2F;&quot;&gt;Webpack&lt;&#x2F;a&gt; or better &lt;a href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;create-react-app&#x2F;&quot;&gt;create-react-app&lt;&#x2F;a&gt; which bring everything you need to develop a &lt;a href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;web&#x2F;progressive-web-apps&#x2F;&quot;&gt;PWA&lt;&#x2F;a&gt; with React and Typescript. Following you can find an example of an app I am developing using create-react-app: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;budget-tracker&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;budget-tracker&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Parcel is a package bundler under development, not as mature as webpack. There are no go errors for me, at least in regards to Typescript support, see this &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;parcel-bundler&#x2F;parcel&#x2F;issues&#x2F;1378&quot;&gt;issue in github #1378&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I still think it is a promising project, bringing more simplicity and speed to JS bundlers world, I will give it a try again for serious projects when Parcel 2 is ready, check &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;parcel-bundler&#x2F;parcel&#x2F;projects&#x2F;5&quot;&gt;Parcel 2 development status&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-start&quot;&gt;Quick start&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;development-server&quot;&gt;Development server&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git clone https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;carlosvin&amp;#x2F;react-typescript-parcel-template.git
cd react-typescript-parcel-template
yarn install
yarn start
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Last &lt;code&gt;yarn start&lt;&#x2F;code&gt; command will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;start a development server at &lt;code&gt;http:&#x2F;&#x2F;localhost:1234&lt;&#x2F;code&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;en.parceljs.org&#x2F;hmr.html&quot;&gt;hot module replacement&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;build automatically development javascript files with source maps&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; Each time you save a file, you will see automatically the result at &lt;code&gt;http:&#x2F;&#x2F;localhost:1234&lt;&#x2F;code&gt; without refreshing the page&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;build-production-bundle&quot;&gt;Build production bundle&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn build
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.parceljs.org&#x2F;production.html#optimisations&quot;&gt;Parcel’s default optimizations&lt;&#x2F;a&gt; will be applied to generated files.&lt;&#x2F;p&gt;
&lt;p&gt;Files are saved at &lt;code&gt;dist&lt;&#x2F;code&gt; folder. Inside &lt;code&gt;dist&lt;&#x2F;code&gt; folder there is also a file with information about bundle content sizes: &lt;code&gt;dist&#x2F;report.html&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;step-by-step-project-creation&quot;&gt;Step by step project creation&lt;&#x2F;h2&gt;
&lt;p&gt;In this section I will describe how I created this project.&lt;&#x2F;p&gt;
&lt;p&gt;Firstly, create &lt;code&gt;package.json&lt;&#x2F;code&gt; with &lt;a href=&quot;https:&#x2F;&#x2F;yarnpkg.com&#x2F;lang&#x2F;en&#x2F;docs&#x2F;cli&#x2F;init&#x2F;&quot;&gt;yarn init&lt;&#x2F;a&gt; command.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn init
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;add-required-dependencies&quot;&gt;Add required dependencies&lt;&#x2F;h3&gt;
&lt;p&gt;Add React dependencies.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn add @types&amp;#x2F;react @types&amp;#x2F;react-dom react react-dom
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Previous command modifies &lt;code&gt;package.json&lt;&#x2F;code&gt; file adding &lt;code&gt;dependencies&lt;&#x2F;code&gt; section and will also install React packages in &lt;code&gt;node_modules&lt;&#x2F;code&gt; folder.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;name&amp;quot;: &amp;quot;project_name&amp;quot;,
  &amp;quot;version&amp;quot;: &amp;quot;1.0.0&amp;quot;,
  &amp;quot;main&amp;quot;: &amp;quot;index.js&amp;quot;,
  &amp;quot;license&amp;quot;: &amp;quot;MIT&amp;quot;,
  &amp;quot;dependencies&amp;quot;: {
    &amp;quot;@types&amp;#x2F;react&amp;quot;: &amp;quot;^16.7.18&amp;quot;,
    &amp;quot;@types&amp;#x2F;react-dom&amp;quot;: &amp;quot;^16.0.11&amp;quot;,
    &amp;quot;react&amp;quot;: &amp;quot;^16.7.0&amp;quot;,
    &amp;quot;react-dom&amp;quot;: &amp;quot;^16.7.0&amp;quot;
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add Typescript compiler as development dependency.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn add --dev typescript
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also need &lt;a href=&quot;https:&#x2F;&#x2F;parceljs.org&#x2F;&quot;&gt;Parcel bundler&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn add --dev parcel-bundler
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I’ve added a non-required dependency, it is a plugin to generate a report of generated bundle contents (the parcel version of &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;webpack-contrib&#x2F;webpack-bundle-analyzer&quot;&gt;webpack-bundle-analyzer&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;yarn add --dev parcel-plugin-bundle-visualiser
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;create-application-source-code&quot;&gt;Create application source code&lt;&#x2F;h3&gt;
&lt;p&gt;First we create the React application in &lt;code&gt;src&#x2F;index.tsx&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;tsx&quot; class=&quot;language-tsx &quot;&gt;&lt;code class=&quot;language-tsx&quot; data-lang=&quot;tsx&quot;&gt;import * as React from &amp;quot;react&amp;quot;;
import * as ReactDOM from &amp;quot;react-dom&amp;quot;;

class App extends React.PureComponent {
    render() {
        return &amp;lt;h1&amp;gt;Hello world!&amp;lt;&amp;#x2F;h1&amp;gt;;
    }
}

ReactDOM.render(
    &amp;lt;App &amp;#x2F;&amp;gt;, 
    document.getElementById(&amp;quot;app&amp;quot;)
);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Parcel can take &lt;code&gt;index.html&lt;&#x2F;code&gt; file as entry file and it figures out how to build the application, so let’s create &lt;code&gt;src&#x2F;index.html&lt;&#x2F;code&gt; as follows:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;html&quot; class=&quot;language-html &quot;&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&amp;lt;html&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;div id=&amp;quot;app&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;div&amp;gt;
    &amp;lt;script src=&amp;quot;.&amp;#x2F;index.tsx&amp;quot;&amp;gt;&amp;lt;&amp;#x2F;script&amp;gt;
  &amp;lt;&amp;#x2F;body&amp;gt;
&amp;lt;&amp;#x2F;html&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We need &lt;code&gt;div&lt;&#x2F;code&gt; tag for React to inject the DOM elements. The &lt;code&gt;script&lt;&#x2F;code&gt; declaration is used by Parcel to find entry point to build.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;add-commands-build-the-project&quot;&gt;Add commands build the project&lt;&#x2F;h3&gt;
&lt;p&gt;I’ve added the commands:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build&lt;&#x2F;code&gt;: Check &lt;em&gt;&quot;Build production bundle&quot;&lt;&#x2F;em&gt; section.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;start&lt;&#x2F;code&gt;: Check &lt;em&gt;&quot;Development server&quot;&lt;&#x2F;em&gt; section.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&amp;quot;scripts&amp;quot;: {
    &amp;quot;start&amp;quot;: &amp;quot;parcel src&amp;#x2F;index.html&amp;quot;,
    &amp;quot;build&amp;quot;: &amp;quot;parcel build src&amp;#x2F;index.html&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then to it is really easy to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;run development server: &lt;code&gt;yarn start&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;generate a production bundle: &lt;code&gt;yarn build&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;There is another approach described in &lt;a href=&quot;https:&#x2F;&#x2F;en.parceljs.org&#x2F;getting_started.html&quot;&gt;Parcel documentation&lt;&#x2F;a&gt; that consists of installing Parcel globally.&lt;&#x2F;p&gt;
&lt;p&gt;I’ve opted for more isolated approach that affects only project you are working on, you just install Parcel as &lt;code&gt;devDependency&lt;&#x2F;code&gt;. There is a tiny drawback, you can’t just run &lt;code&gt;parcel index.html&lt;&#x2F;code&gt;, because it is not installed in your system, but in &lt;code&gt;node_modules&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;There is a simple way to run any binary installed in &lt;code&gt;node_modules&lt;&#x2F;code&gt;, you can just run &lt;code&gt;npx parcel index.html&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I like more to define build steps in &lt;code&gt;package.json&lt;&#x2F;code&gt; file, so you can have well defined commands more suited to build your project. You can also use these commands as documentation how to build your project.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;configure-typescript-optional&quot;&gt;Configure Typescript (optional)&lt;&#x2F;h3&gt;
&lt;p&gt;Create a &lt;code&gt;tsconfig.json&lt;&#x2F;code&gt; file:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
    &amp;quot;compilerOptions&amp;quot;: {
        &amp;quot;outDir&amp;quot;: &amp;quot;.&amp;#x2F;dist&amp;#x2F;&amp;quot;,
        &amp;quot;sourceMap&amp;quot;: true,
        &amp;quot;noImplicitAny&amp;quot;: true,
        &amp;quot;module&amp;quot;: &amp;quot;commonjs&amp;quot;,
        &amp;quot;target&amp;quot;: &amp;quot;es5&amp;quot;,
        &amp;quot;jsx&amp;quot;: &amp;quot;react&amp;quot;
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this configuration, Typescript compiler will:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Generate files in &lt;code&gt;dist&lt;&#x2F;code&gt; folder.&lt;&#x2F;li&gt;
&lt;li&gt;Generate &lt;a href=&quot;https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Tools&#x2F;Debugger&#x2F;How_to&#x2F;Use_a_source_map&quot;&gt;source maps&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Will not allow to declare &lt;code&gt;any&lt;&#x2F;code&gt; type, for example following declaration is not allowed: &lt;code&gt;const elements: any;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Generated module code will be &lt;a href=&quot;https:&#x2F;&#x2F;requirejs.org&#x2F;docs&#x2F;commonjs.html&quot;&gt;CommonJs&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Generated code will be &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;ECMAScript&quot;&gt;ECMAScript&lt;&#x2F;a&gt; 5 compliant.&lt;&#x2F;li&gt;
&lt;li&gt;Support &lt;a href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;docs&#x2F;handbook&#x2F;jsx.html&quot;&gt;JSX&lt;&#x2F;a&gt; in &lt;code&gt;.tsx&lt;&#x2F;code&gt; files.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;full-source-code&quot;&gt;Full source code&lt;&#x2F;h2&gt;
&lt;p&gt;You can find full example at: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;react-typescript-parcel-template&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;react-typescript-parcel-template&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Or you can directly download the source code:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;react-typescript-parcel-template&#x2F;archive&#x2F;1.0.zip&quot;&gt;zip&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;react-typescript-parcel-template&#x2F;archive&#x2F;1.0.tar.gz&quot;&gt;tar.gz&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Custom Maven Plugin - Override default build lifecycle</title>
        <published>2018-05-12T00:00:00+00:00</published>
        <updated>2018-05-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/creating-custom-maven-plugin-default/"/>
        <id>https://carlosvin.github.io/creating-custom-maven-plugin-default/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/creating-custom-maven-plugin-default/">&lt;p&gt;I explained in previous article &lt;a href=&quot;&#x2F;langs&#x2F;en&#x2F;posts&#x2F;creating-custom-maven-plugin&quot;&gt;Example how to create custom Maven Plugin&lt;&#x2F;a&gt; which &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;ref&#x2F;3.5.3&#x2F;maven-core&#x2F;lifecycles.html#site_Lifecycle&quot;&gt;overrides site lifecycle&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I have created another example to demonstrate how to override &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;ref&#x2F;3.5.3&#x2F;maven-core&#x2F;lifecycles.html#default_Lifecycle&quot;&gt;default Maven build lifecycle&lt;&#x2F;a&gt;. Default build lifecycle is used to construct your software project, for example, it is executed when you run &lt;code&gt;mvn install&lt;&#x2F;code&gt; in a &lt;code&gt;jar&lt;&#x2F;code&gt; type project.&lt;&#x2F;p&gt;
&lt;p&gt;You can find source code example at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;lifecycle-maven-plugin&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;lifecycle-maven-plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; I&#x27;ve also created an &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;guides&#x2F;introduction&#x2F;introduction-to-archetypes.html&quot;&gt;archetype&lt;&#x2F;a&gt; so you can easily play with the example.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;create-an-example-project&quot;&gt;Create an example project&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;generate-the-project-using-archetype&quot;&gt;Generate the project using archetype&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mvn archetype:generate \
  -DarchetypeGroupId=com.github.carlosvin.archetype \
  -DartifactId=lifecycle-maven-plugin-archetype \
  -DarchetypeVersion=0.6
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Example how to create custom Maven Plugin</title>
        <published>2018-03-11T00:00:00+00:00</published>
        <updated>2018-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/creating-custom-maven-plugin/"/>
        <id>https://carlosvin.github.io/creating-custom-maven-plugin/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/creating-custom-maven-plugin/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&quot;&gt;Maven&lt;&#x2F;a&gt; has lots of plugins to assist you in project construction, testing, packaging and deployment. For example if you want to compile C++ code instead of Java, you can use &lt;a href=&quot;https:&#x2F;&#x2F;www.mojohaus.org&#x2F;maven-native&#x2F;native-maven-plugin&#x2F;&quot;&gt;native-maven-plugin&lt;&#x2F;a&gt;. But what if you need something more specific? Then you can create a custom Maven plugin.&lt;&#x2F;p&gt;
&lt;p&gt;I will explain how to create a simple custom maven plugin to generate static blog site from Markdown files. I know we can already do that with &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;plugins&#x2F;maven-site-plugin&#x2F;examples&#x2F;creating-content.html&quot;&gt;maven-site-plugin&lt;&#x2F;a&gt; since version 3.3, I will just use it for learning purposes.&lt;&#x2F;p&gt;
&lt;p&gt;You can find the source code of this example at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;maven-plugin-concepts&quot;&gt;Maven plugin concepts&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Mojo:&lt;&#x2F;strong&gt; An executable goal in Maven, e.g: &lt;code&gt;mvn your-plugin:your-mojo&lt;&#x2F;code&gt; will execute a maven goal &lt;code&gt;your-mojo&lt;&#x2F;code&gt; declared as part of &lt;code&gt;your-plugin&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Goal:&lt;&#x2F;strong&gt; It is equivalent to Mojo execution.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Lifecycle:&lt;&#x2F;strong&gt; It is a well-defined sequence of phases. Each phase consists of a sequence of goals. Let&#x27;s see an example of lifecycle, e.g: &lt;code&gt;FooLifecycle&lt;&#x2F;code&gt; has &lt;code&gt;clean&lt;&#x2F;code&gt;, &lt;code&gt;prepare&lt;&#x2F;code&gt; and &lt;code&gt;assemble&lt;&#x2F;code&gt; phases. Each of those phases has one of more goals. &lt;em&gt;FooLifecycle&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;clean:
&lt;ul&gt;
&lt;li&gt;rmSources: a goal to remove source files&lt;&#x2F;li&gt;
&lt;li&gt;rmBuild: a goal to remove files in cache directory&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;prepare:
&lt;ul&gt;
&lt;li&gt;installDependencies: a goal to download dependencies for the project&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;assemble:
&lt;ul&gt;
&lt;li&gt;build: a goal to compile source files&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To define a custom life-cycle similar to previous one, we will use &lt;code&gt;src&#x2F;main&#x2F;resources&#x2F;META-INF&#x2F;plexus&#x2F;components.xml&lt;&#x2F;code&gt;, we will speak about that file in following sections. Normally is enough to override &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;ref&#x2F;3.5.3&#x2F;maven-core&#x2F;lifecycles.html&quot;&gt;predefined lifecycles&lt;&#x2F;a&gt;, in this example, we will override &lt;em&gt;site life-cycle&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; You can find an introduction to Maven life-cycles at &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;guides&#x2F;introduction&#x2F;introduction-to-the-lifecycle.html&quot;&gt;Maven life-cycle guide&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;create-your-custom-plugin-site-lifecycle&quot;&gt;Create your custom plugin (Site Lifecycle)&lt;&#x2F;h2&gt;
&lt;p&gt;The plugin we are about to explain will &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;ref&#x2F;3.5.3&#x2F;maven-core&#x2F;lifecycles.html#site_Lifecycle&quot;&gt;override site lifecycle&lt;&#x2F;a&gt;, which has only 2 default phases, so when we run &lt;code&gt;mvn site&lt;&#x2F;code&gt; using our new custom plugin it will execute the goals we are about to create.&lt;&#x2F;p&gt;
&lt;p&gt;Our plugin will work with &lt;code&gt;md&lt;&#x2F;code&gt; (for &lt;a href=&quot;https:&#x2F;&#x2F;commonmark.org&#x2F;&quot;&gt;Markdown&lt;&#x2F;a&gt;) file bindings: It will build and deploy the project using &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;plugins&#x2F;maven-deploy-plugin&#x2F;&quot;&gt;maven deployment plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;project-structure&quot;&gt;Project structure&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;src&#x2F;main&#x2F;java&lt;&#x2F;code&gt;: Where Java source code is&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;src&#x2F;main&#x2F;resources&#x2F;META-INF&#x2F;plexus&#x2F;components.xml&lt;&#x2F;code&gt;: file to create&#x2F;override maven lifecycles and artifact types. Here we can specify which goals will be executed when for an artifact type, for example, we can say that for an artifact of type &lt;code&gt;whatever&lt;&#x2F;code&gt; when we run &lt;code&gt;mvn foo&lt;&#x2F;code&gt; it will verify the files, run tests, run linter, compile and zip all generated files.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;src&#x2F;test&#x2F;java&lt;&#x2F;code&gt;: Unit tests folder.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;src&#x2F;it&lt;&#x2F;code&gt;: Folder with all integration tests. Those integration tests are running actual projects and checking that outputs are as expected.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pom.xml&lt;&#x2F;code&gt;: File with Maven project description (&lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;guides&#x2F;introduction&#x2F;introduction-to-the-pom.html&quot;&gt;Project Object Model&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dependency-injection&quot;&gt;Dependency Injection&lt;&#x2F;h3&gt;
&lt;p&gt;Maven has finally chosen &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;maven-jsr330.html&quot;&gt;JSR-330&lt;&#x2F;a&gt; as &lt;a href=&quot;https:&#x2F;&#x2F;javax-inject.github.io&#x2F;javax-inject&#x2F;&quot;&gt;dependency injection standard&lt;&#x2F;a&gt; (previously it was Plexus Annotations API).&lt;&#x2F;p&gt;
&lt;p&gt;To use dependency injection with Maven we have to:&lt;&#x2F;p&gt;
&lt;p&gt;Add &lt;code&gt;javax.inject&lt;&#x2F;code&gt; dependency to &lt;code&gt;pom.xml&lt;&#x2F;code&gt;, so we can use &lt;code&gt;@Inject&lt;&#x2F;code&gt;, &lt;code&gt;@Named&lt;&#x2F;code&gt;, and &lt;code&gt;@Singleton&lt;&#x2F;code&gt; annotations in plugin implementation Java code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pom-xml-dependency&quot;&gt;pom.xml (Dependency)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax.inject&amp;lt;&amp;#x2F;groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javax.inject&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;1&amp;lt;&amp;#x2F;version&amp;gt;
&amp;lt;&amp;#x2F;dependency&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Set up the &lt;code&gt;sisu-maven-plugin&lt;&#x2F;code&gt; to index the JSR-330 components you want made available to Maven.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pom-xml-plugin&quot;&gt;pom.xml (Plugin)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;org.eclipse.sisu&amp;lt;&amp;#x2F;groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;sisu-maven-plugin&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.3.3&amp;lt;&amp;#x2F;version&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;generate-index&amp;lt;&amp;#x2F;id&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;main-index&amp;lt;&amp;#x2F;goal&amp;gt;
            &amp;lt;&amp;#x2F;goals&amp;gt;
        &amp;lt;&amp;#x2F;execution&amp;gt;
    &amp;lt;&amp;#x2F;executions&amp;gt;
&amp;lt;&amp;#x2F;plugin&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Add annotations to your Mojo, e.g:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;buildmojo-java-dependency-injection&quot;&gt;BuildMojo.java (Dependency Injection)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Mojo(name = &amp;quot;build&amp;quot;, defaultPhase = LifecyclePhase.COMPILE) &amp;#x2F;&amp;#x2F; &amp;lt;1&amp;gt;
public class BuildMojo extends AbstractMojo {

    private final FileSetManager fileSetManager;
    private final MdToHtml mdToHtml;

    @Inject &amp;#x2F;&amp;#x2F; &amp;lt;2&amp;gt;
    public BuildMojo(FileSetManager fileSetManager, MdToHtml mdToHtml) {
        this.fileSetManager = fileSetManager;
        this.mdToHtml = mdToHtml;
        &amp;#x2F;&amp;#x2F;
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;This annotation is not a dependency injection one, we will explain later what it is for.&lt;&#x2F;li&gt;
&lt;li&gt;It will inject an instance of FileSetManager and MdToHtml.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;write-a-custom-mojo&quot;&gt;Write a custom Mojo&lt;&#x2F;h3&gt;
&lt;p&gt;It is quite straightforward to implement a Mojo class, we have to:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;1-implement-mojo-interface&quot;&gt;1. Implement Mojo interface&lt;&#x2F;h4&gt;
&lt;p&gt;Your Mojo class has to implement &lt;code&gt;org.apache.maven.plugin.Mojo&lt;&#x2F;code&gt;, although it is more convenient to extend &lt;code&gt;org.apache.maven.plugin.AbstractMojo&lt;&#x2F;code&gt;, an abstract class to provide most of the infrastructure required to implement a Mojo except for execute method. That interface and class are described at &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;developers&#x2F;mojo-api-specification.html&quot;&gt;Mojo API&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public class BuildMojo extends AbstractMojo { 
    &amp;#x2F;&amp;#x2F; ...
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;2-configure-mojo-with-java-5-annotations&quot;&gt;2. Configure Mojo with Java 5 annotations&lt;&#x2F;h4&gt;
&lt;p&gt;Annotate Mojo class with &lt;code&gt;@Mojo&lt;&#x2F;code&gt; and input parameters with &lt;code&gt;@Parameter&lt;&#x2F;code&gt;. Those annotations belong to another set of annotations to configure Mojos, &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;plugin-tools&#x2F;maven-plugin-plugin&#x2F;examples&#x2F;using-annotations.html&quot;&gt;Plugin Tools Java5 Annotations&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&amp;#x2F;**
* Generate HTML files from Markdown files
*&amp;#x2F;
@Mojo(name = &amp;quot;build&amp;quot;, defaultPhase = LifecyclePhase.COMPILE) &amp;#x2F;&amp;#x2F; &amp;lt;1&amp;gt;
public class BuildMojo extends AbstractMojo {

    &amp;#x2F;**
    * Output directory path where HTML files are generated
    *&amp;#x2F;
    @Parameter( &amp;#x2F;&amp;#x2F; &amp;lt;2&amp;gt;
      defaultValue = &amp;quot;${project.reporting.outputDirectory}&amp;quot;, &amp;#x2F;&amp;#x2F; &amp;lt;3&amp;gt;
      property = &amp;quot;siteOutputDirectory&amp;quot;, &amp;#x2F;&amp;#x2F; &amp;lt;4&amp;gt;
      required = true) 
    private File outputDirectory;

    &amp;#x2F;**
    * A specific &amp;lt;code&amp;gt;fileSet&amp;lt;&amp;#x2F;code&amp;gt; rule to select files and directories.
    * Fileset spec: https:&amp;#x2F;&amp;#x2F;maven.apache.org&amp;#x2F;shared&amp;#x2F;file-management&amp;#x2F;fileset.html
    *&amp;#x2F;
    @Parameter
    private FileSet inputFiles;
    &amp;#x2F;&amp;#x2F; 
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;Configures Mojo name and default life-cycle phase. To execute the Mojo in this example we will use &lt;code&gt;mvn site:build&lt;&#x2F;code&gt;: &lt;em&gt;site&lt;&#x2F;em&gt; is the plugin name and &lt;em&gt;build&lt;&#x2F;em&gt; is &lt;code&gt;name&lt;&#x2F;code&gt; parameter.&lt;&#x2F;li&gt;
&lt;li&gt;We use &lt;code&gt;@Parameter&lt;&#x2F;code&gt; annotation to pass configuration parameters to Mojo.&lt;&#x2F;li&gt;
&lt;li&gt;You can use properties placeholder or any String. If the parameter type is not a String, then Maven will try to cast it.&lt;&#x2F;li&gt;
&lt;li&gt;It allows configuration of the Mojo parameter from the command line by referencing a system property that the user sets via the -D option. E.g: &lt;code&gt;mvn site:build -DsiteOutputDirectory=&#x2F;var&#x2F;www&#x2F;html&lt;&#x2F;code&gt; will set siteOutputDirectory attribute to &lt;code&gt;&#x2F;var&#x2F;www&#x2F;html&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; More info in &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;guides&#x2F;plugin&#x2F;guide-java-plugin-development.html#Parameters&quot;&gt;Maven Plugin development guide in Parameters section&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;3-implement-execute-method&quot;&gt;3. Implement &lt;em&gt;execute&lt;&#x2F;em&gt; method&lt;&#x2F;h4&gt;
&lt;p&gt;As I have explained before at &lt;strong&gt;1. Implement Mojo interface&lt;&#x2F;strong&gt;, our Mojo class extends &lt;code&gt;org.apache.maven.plugin.AbstractMojo&lt;&#x2F;code&gt; which has one unimplemented method from &lt;code&gt;org.apache.maven.plugin.Mojo&lt;&#x2F;code&gt; interface. In that method we are going to implement the Maven goal logic.&lt;&#x2F;p&gt;
&lt;p&gt;Mojo class instance is called from Maven execution life-cycle by invoking &lt;code&gt;execute()&lt;&#x2F;code&gt; method. Before calling &lt;code&gt;execute()&lt;&#x2F;code&gt;, Maven has performed some other tasks related with the Mojo:&lt;&#x2F;p&gt;
&lt;p&gt;Maven instantiates Mojo and injects dependencies (see &lt;strong&gt;Dependency Injection&lt;&#x2F;strong&gt; section).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;Mojo mojo = new BuildMojo(fileSetManager, mdToHtml);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Maven configures the Mojo by assigning values to parameters.&lt;&#x2F;p&gt;
&lt;p&gt;I will simplify &lt;code&gt;execute&lt;&#x2F;code&gt; method implementation in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&quot;&gt;sample project in github&lt;&#x2F;a&gt;, because it is more complicated and this complexity is not relevant for learning purposes.&lt;&#x2F;p&gt;
&lt;p&gt;Maven calls execute method: &lt;code&gt;mojo.execute()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;buildmojo-java-execute-method&quot;&gt;BuildMojo.java (Execute Method)&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public void execute() throws MojoExecutionException { &amp;#x2F;&amp;#x2F; &amp;lt;1&amp;gt;
    if (inputFiles == null) {
        setDefaultInput();
    }
    inputDirPath = Paths.get(inputFiles.getDirectory());

    String[] includedFiles = fileSetManager.getIncludedFiles(inputFiles); &amp;#x2F;&amp;#x2F; &amp;lt;2&amp;gt;

    outputDirPath = outputDirectory.toPath();
    if (includedFiles == null || includedFiles.length == 0) {
        getLog().warn(&amp;quot;SKIP: There are no input files. &amp;quot; + getInputFilesToString()); &amp;#x2F;&amp;#x2F; &amp;lt;3&amp;gt;
    } else {
        if (!outputDirectory.exists()) { &amp;#x2F;&amp;#x2F; &amp;lt;4&amp;gt;
            outputDirectory.mkdirs();
        }
        try {
            for (String f : includedFiles) {
                convertToHtml(Paths.get(f), outputDirectory); &amp;#x2F;&amp;#x2F; &amp;lt;5&amp;gt;
            }
        } catch (InterruptedException e) {
            throw new MojoExecutionException(e.getLocalizedMessage(), e); &amp;#x2F;&amp;#x2F; &amp;lt;6&amp;gt;
        }
    }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;If there is any error during execution, it should throw MojoExecutionException.&lt;&#x2F;li&gt;
&lt;li&gt;A way to get all selected files from &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;shared&#x2F;file-management&#x2F;fileset.html&quot;&gt;FileSet&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;AbstractMojo supplies logger functionality.&lt;&#x2F;li&gt;
&lt;li&gt;If output directory doesn&#x27;t exist, it will be created.&lt;&#x2F;li&gt;
&lt;li&gt;It converts each file Markdown to HTML.&lt;&#x2F;li&gt;
&lt;li&gt;Convert thrown exception to MojoExecutionException.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;unit-tests&quot;&gt;Unit tests&lt;&#x2F;h2&gt;
&lt;p&gt;In the example we use &lt;a href=&quot;https:&#x2F;&#x2F;junit.org&#x2F;junit4&#x2F;&quot;&gt;JUnit 4&lt;&#x2F;a&gt;, but you can use any other testing framework.&lt;&#x2F;p&gt;
&lt;p&gt;Firstly, you have to add the unit test library dependency to &lt;code&gt;pom.xml&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pom-xml&quot;&gt;pom.xml&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;junit&amp;lt;&amp;#x2F;groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;junit&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;4.11&amp;lt;&amp;#x2F;version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;&amp;#x2F;scope&amp;gt;
&amp;lt;&amp;#x2F;dependency&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you just have to write your unit tests under &lt;code&gt;src&#x2F;test&#x2F;java&lt;&#x2F;code&gt; folder: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&#x2F;blob&#x2F;master&#x2F;src&#x2F;test&#x2F;java&#x2F;com&#x2F;maven&#x2F;plugins&#x2F;blog&#x2F;PathsTest.java&quot;&gt;src&#x2F;test&#x2F;java&#x2F;com&#x2F;maven&#x2F;plugins&#x2F;blog&#x2F;PathsTest.java&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To run the unit tests you just need to execute &lt;code&gt;mvn test&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;integration-tests&quot;&gt;Integration tests&lt;&#x2F;h2&gt;
&lt;p&gt;The 2 most popular ways to perform integration tests on custom maven plugins are using &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;surefire&#x2F;maven-failsafe-plugin&quot;&gt;maven-failsafe-plugin&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;plugins&#x2F;maven-invoker-plugin&quot;&gt;maven-invoker-plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve chosen maven-invoker-plugin because for me it is more straightforward. There is &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;40010745&#x2F;maven-invoker-plugin-vs-maven-failsafe-plugin-which-to-use-for-integration-test&quot;&gt;an answer at stackoverflow where they explain thoroughly the differences between them&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-does-invoker-plugin-work&quot;&gt;How does Invoker Plugin work?&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;We create projects to use our custom plugin under &lt;code&gt;src&#x2F;it&lt;&#x2F;code&gt; folder, so our plugin will be applied to test projects.&lt;&#x2F;li&gt;
&lt;li&gt;Invoker plugin will simulate a previously configured Maven execution.&lt;&#x2F;li&gt;
&lt;li&gt;After Maven execution, a validation script will check if our plugin outputs are the expected ones. For example, if our plugin is supposed to generate a file named &lt;code&gt;foo.file&lt;&#x2F;code&gt;, verification plugin will check if that file exists, if it doesn&#x27;t, integration test will fail.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;configure-invoker-plugin&quot;&gt;Configure Invoker Plugin&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;plugin&amp;gt;
    &amp;lt;artifactId&amp;gt;maven-invoker-plugin&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.0.1&amp;lt;&amp;#x2F;version&amp;gt;
    &amp;lt;configuration&amp;gt;
        &amp;lt;postBuildHookScript&amp;gt;verify&amp;lt;&amp;#x2F;postBuildHookScript&amp;gt; &amp;lt;!-- 3 --&amp;gt;
        &amp;lt;showVersion&amp;gt;true&amp;lt;&amp;#x2F;showVersion&amp;gt;
        &amp;lt;streamLogs&amp;gt;true&amp;lt;&amp;#x2F;streamLogs&amp;gt;
        &amp;lt;noLog&amp;gt;false&amp;lt;&amp;#x2F;noLog&amp;gt;
        &amp;lt;showErrors&amp;gt;true&amp;lt;&amp;#x2F;showErrors&amp;gt;
    &amp;lt;&amp;#x2F;configuration&amp;gt;
    &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
            &amp;lt;id&amp;gt;integration-test&amp;lt;&amp;#x2F;id&amp;gt;
            &amp;lt;goals&amp;gt;
                &amp;lt;goal&amp;gt;install&amp;lt;&amp;#x2F;goal&amp;gt; &amp;lt;!-- 1 --&amp;gt;
                &amp;lt;goal&amp;gt;run&amp;lt;&amp;#x2F;goal&amp;gt; &amp;lt;!-- 2 --&amp;gt;
            &amp;lt;&amp;#x2F;goals&amp;gt;
        &amp;lt;&amp;#x2F;execution&amp;gt;
    &amp;lt;&amp;#x2F;executions&amp;gt;
&amp;lt;&amp;#x2F;plugin&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;invoker:install&lt;&#x2F;code&gt; will be executed during the phase pre-integration-test and will install the main project artifact into target&#x2F;local-repo.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;invoker:run&lt;&#x2F;code&gt; will be executed during the integration-test phase and it will execute all defined integration tests under &lt;code&gt;src&#x2F;it&lt;&#x2F;code&gt; folder.&lt;&#x2F;li&gt;
&lt;li&gt;It configures invoker plugin to execute validation script after integration test project execution. This script may be written with either BeanShell or Groovy (verify.groovy or verify.bsh).&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;We have used other properties to show errors, show maven log and save it to a file.&lt;&#x2F;p&gt;
&lt;p&gt;You can check all &lt;code&gt;invoker:run&lt;&#x2F;code&gt; configuration properties at &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;plugins&#x2F;maven-invoker-plugin&#x2F;run-mojo.html&quot;&gt;maven-invoker-plugin run-mojo&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-an-integration-test-project&quot;&gt;Create an Integration Test Project&lt;&#x2F;h3&gt;
&lt;p&gt;It is a project we use to execute custom plugin goals, so we can validate if it produces the expected output.&lt;&#x2F;p&gt;
&lt;p&gt;There are 3 important files matching with &lt;a href=&quot;http:&#x2F;&#x2F;wiki.c2.com&#x2F;?ArrangeActAssert&quot;&gt;AAA&lt;&#x2F;a&gt; phases (&quot;Arrange-Act-Assert&quot;).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;arrange-pom-xml&quot;&gt;Arrange: pom.xml&lt;&#x2F;h4&gt;
&lt;p&gt;This file is a project using our custom plugin.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&#x2F;blob&#x2F;master&#x2F;src&#x2F;it&#x2F;md-html&#x2F;pom.xml&quot;&gt;src&#x2F;it&#x2F;md-html&#x2F;pom.xml&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;project xmlns=&amp;quot;http:&amp;#x2F;&amp;#x2F;maven.apache.org&amp;#x2F;POM&amp;#x2F;4.0.0&amp;quot; xmlns:xsi=&amp;quot;http:&amp;#x2F;&amp;#x2F;www.w3.org&amp;#x2F;2001&amp;#x2F;XMLSchema-instance&amp;quot;
xsi:schemaLocation=&amp;quot;http:&amp;#x2F;&amp;#x2F;maven.apache.org&amp;#x2F;POM&amp;#x2F;4.0.0 http:&amp;#x2F;&amp;#x2F;maven.apache.org&amp;#x2F;xsd&amp;#x2F;maven-4.0.0.xsd&amp;quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;&amp;#x2F;modelVersion&amp;gt;

    &amp;lt;groupId&amp;gt;com.maven.plugins.it&amp;lt;&amp;#x2F;groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;simple-it&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;&amp;#x2F;version&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;@project.groupId@&amp;lt;&amp;#x2F;groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;@project.artifactId@&amp;lt;&amp;#x2F;artifactId&amp;gt;
                &amp;lt;version&amp;gt;@project.version@&amp;lt;&amp;#x2F;version&amp;gt;
            &amp;lt;&amp;#x2F;plugin&amp;gt;
        &amp;lt;&amp;#x2F;plugins&amp;gt;
    &amp;lt;&amp;#x2F;build&amp;gt;
&amp;lt;&amp;#x2F;project&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is a very simple pom file where we use placeholders to reference to our plugin under test. When invoker plugin executes following pom file, firstly will replace those placeholders to reference to the latest version of our custom plugin which was recently installed in the local repository:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;xml&quot; class=&quot;language-xml &quot;&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&amp;lt;plugin&amp;gt;
    &amp;lt;groupId&amp;gt;com.maven.plugins&amp;lt;&amp;#x2F;groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;blog&amp;lt;&amp;#x2F;artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.0.1-SNAPSHOT&amp;lt;&amp;#x2F;version&amp;gt;
&amp;lt;&amp;#x2F;plugin&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In that way invoker plugin ensures it is testing the latest version of current project.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;act-invoker-properties&quot;&gt;Act: invoker.properties&lt;&#x2F;h4&gt;
&lt;p&gt;It configures how test project will be executed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&#x2F;blob&#x2F;master&#x2F;src&#x2F;it&#x2F;md-html&#x2F;invoker.properties&quot;&gt;src&#x2F;it&#x2F;md-html&#x2F;invoker.properties&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;properties&quot; class=&quot;language-properties &quot;&gt;&lt;code class=&quot;language-properties&quot; data-lang=&quot;properties&quot;&gt;invoker.goals = blog:build
invoker.name = Test build MD
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will execute &lt;code&gt;mvn blog:build&lt;&#x2F;code&gt;, a goal defined in our custom plugin under example or what is the same, it will execute BuildMojo described in section &lt;strong&gt;Write a custom Mojo&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;assert-verify-groovy&quot;&gt;Assert: verify.groovy&lt;&#x2F;h4&gt;
&lt;p&gt;It is the script to check that plugin execution generated the expected results.&lt;&#x2F;p&gt;
&lt;p&gt;Verification script, it is checking if &lt;code&gt;target&#x2F;site&#x2F;README.html&lt;&#x2F;code&gt; file was generated by the plugin.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;blog-maven-plugin&#x2F;blob&#x2F;master&#x2F;src&#x2F;it&#x2F;md-html&#x2F;verify.groovy&quot;&gt;src&#x2F;it&#x2F;md-html&#x2F;verify.groovy&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;groovy&quot; class=&quot;language-groovy &quot;&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;File generated = new File( basedir, &amp;quot;target&amp;#x2F;site&amp;#x2F;README.html&amp;quot; );

assert generated.isFile()
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Choosing a Modern C++ stack</title>
        <published>2017-09-15T00:00:00+00:00</published>
        <updated>2020-06-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/choosing-modern-cpp-stack/"/>
        <id>https://carlosvin.github.io/choosing-modern-cpp-stack/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/choosing-modern-cpp-stack/">&lt;p&gt;I&#x27;m starting a new project in C++, but I&#x27;ve run into a couple of questions before starting:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Which build system should I use?&lt;&#x2F;li&gt;
&lt;li&gt;Which unit testing framework?&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;&#x2F;strong&gt;: If you just want a project template so you can have a C++ project skeleton ready in seconds, just go to &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&quot;&gt;uuid-cpp&lt;&#x2F;a&gt; and follow the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&#x2F;blob&#x2F;master&#x2F;README.md&quot;&gt;instructions in README.md&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;choosing-build-system-meson&quot;&gt;Choosing Build System (&lt;a href=&quot;https:&#x2F;&#x2F;mesonbuild.com&#x2F;&quot;&gt;Meson&lt;&#x2F;a&gt;)&lt;&#x2F;h2&gt;
&lt;p&gt;I have used before &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;make.html&quot;&gt;Make&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&#x2F;&quot;&gt;Maven&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;scons.org&#x2F;&quot;&gt;Scons&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;gradle.org&#x2F;&quot;&gt;Gradle&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;automake&#x2F;manual&#x2F;html_node&#x2F;Autotools-Introduction.html&quot;&gt;Autotools&lt;&#x2F;a&gt;, but I have some reasons to try something else:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Autotools:&lt;&#x2F;strong&gt; It is not easy to configure and maintain. There are several configuration files and several configuration steps.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Gradle:&lt;&#x2F;strong&gt; CPP feature is still incubating. Not very fast. You can check a similar example project at &lt;a href=&quot;&#x2F;langs&#x2F;en&#x2F;posts&#x2F;gradle-cpp&quot;&gt;Build C++ project with Gradle&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Make:&lt;&#x2F;strong&gt; I don&#x27;t love the syntax. Files tend to get messy as the project grows.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Scons:&lt;&#x2F;strong&gt; It is just slower and not as easy to understand as Meson.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Maven:&lt;&#x2F;strong&gt; It is slow and you might end up &quot;Javatizing&quot; your C++ project structure.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: I&#x27;ve listed just things I don&#x27;t like; those projects have other great features.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;cmake-vs-meson&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;cmake.org&#x2F;&quot;&gt;CMake&lt;&#x2F;a&gt; vs &lt;a href=&quot;https:&#x2F;&#x2F;mesonbuild.com&#x2F;&quot;&gt;Meson&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;p&gt;After discarding previous ones, I&#x27;m considering Meson or CMake. Both are fast build systems:&lt;&#x2F;p&gt;
&lt;p&gt;Although Meson is written in &lt;a href=&quot;https:&#x2F;&#x2F;python.org&#x2F;&quot;&gt;Python&lt;&#x2F;a&gt;, it generates a &lt;a href=&quot;https:&#x2F;&#x2F;ninja-build.org&#x2F;&quot;&gt;Ninja&lt;&#x2F;a&gt; build project. The first time you configure the project you have to run Meson, but for building or testing you are actually running Ninja.&lt;&#x2F;p&gt;
&lt;p&gt;CMake can also generate Ninja files among other formats; &lt;a href=&quot;https:&#x2F;&#x2F;cmake.org&#x2F;cmake&#x2F;help&#x2F;latest&#x2F;manual&#x2F;cmake-generators.7.html&quot;&gt;check CMake generators documentation for more information&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CMake:&lt;&#x2F;strong&gt; It has a big advantage over Meson; it is mature and widely used in many projects, which means there are many examples and it will fulfill your C++ project building needs.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Meson:&lt;&#x2F;strong&gt; It is a young project compared with CMake, but it is growing quite fast and it has been adopted in other big projects like &lt;a href=&quot;https:&#x2F;&#x2F;www.gnome.org&#x2F;&quot;&gt;Gnome&lt;&#x2F;a&gt;, which has an initiative to &lt;a href=&quot;https:&#x2F;&#x2F;wiki.gnome.org&#x2F;Initiatives&#x2F;GnomeGoals&#x2F;MesonPorting&quot;&gt;port from Autotools to Meson&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;Finally, I&#x27;ve chosen&lt;&#x2F;strong&gt; Meson because syntax is really clear to me; when I read a &lt;code&gt;meson.build&lt;&#x2F;code&gt; file I can quickly understand what is happening during the build process.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;steps-to-compile-and-test-a-project&quot;&gt;Steps to compile and test a project&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;meson build .  # First time you configure the project
cd build
ninja build    # Each time you build it
ninja test     # Each time you run tests
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;First time you configure the project&lt;&#x2F;li&gt;
&lt;li&gt;Each time you build it&lt;&#x2F;li&gt;
&lt;li&gt;Each time you run tests&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;other-build-systems-comparisons&quot;&gt;Other build systems comparisons&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x27;ve found two interesting comparisons about available C++ build systems; they might be a little biased because those comparisons come from Meson and Scons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;bitbucket.org&#x2F;scons&#x2F;scons&#x2F;wiki&#x2F;SconsVsOtherBuildTools&quot;&gt;C++ build systems comparison from Scons&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;mesonbuild.com&#x2F;Simple-comparison.html&quot;&gt;C++ build systems comparison from Meson&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;unit-testing-framework&quot;&gt;Unit Testing Framework&lt;&#x2F;h2&gt;
&lt;p&gt;I have used some &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;XUnit&quot;&gt;xUnit&lt;&#x2F;a&gt;-based libraries like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;unittest-cpp&#x2F;unittest-cpp&quot;&gt;UnitTest++&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;cpputest.github.io&#x2F;&quot;&gt;CppUTest&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;googletest&quot;&gt;Google Test&lt;&#x2F;a&gt;, which pair perfectly with &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;google&#x2F;googletest&#x2F;tree&#x2F;master&#x2F;googlemock&quot;&gt;Google Mock&lt;&#x2F;a&gt;. If you want a safe bet that fulfills almost all of your testing needs I highly recommend Google Test.&lt;&#x2F;p&gt;
&lt;p&gt;But some time ago I found a testing framework with some interesting features: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;philsquared&#x2F;Catch&quot;&gt;Catch&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;It is just a header file with no external dependencies, so very easy to start (wget + include downloaded file).&lt;&#x2F;li&gt;
&lt;li&gt;You can use normal unit test style or &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Behavior-driven_development&quot;&gt;BDD&lt;&#x2F;a&gt;-style.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you want to know more about Catch, I recommend you to give it a try; it takes just 2 minutes to have a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;philsquared&#x2F;Catch&#x2F;blob&#x2F;master&#x2F;docs&#x2F;tutorial.md#writing-tests&quot;&gt;simple example up and running&lt;&#x2F;a&gt;. You can also read some interesting articles like &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;philsquared&#x2F;Catch&#x2F;blob&#x2F;master&#x2F;docs&#x2F;why-catch.md&quot;&gt;Why do we need yet another C++ test framework?&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;blog.coldflake.com&#x2F;posts&#x2F;Testing-C++-with-a-new-Catch&#x2F;&quot;&gt;Testing C++ With A New Catch&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;doctest-a-catch-alternative&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;onqtam&#x2F;doctest&quot;&gt;Doctest&lt;&#x2F;a&gt;: A Catch alternative&lt;&#x2F;h3&gt;
&lt;p&gt;There is another testing framework named Doctest, with the same benefits as Catch, but it promises to be faster and lighter (&lt;a href=&quot;&#x2F;content&#x2F;blog&#x2F;serialization-java-serializable-externalizable.en.md&quot;&gt;performance results&lt;&#x2F;a&gt;) than Catch.&lt;&#x2F;p&gt;
&lt;p&gt;Doctest is modeled after Catch and some parts of the code have been taken directly, but there are &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;onqtam&#x2F;doctest&#x2F;blob&#x2F;master&#x2F;doc&#x2F;markdown&#x2F;faq.md#how-is-doctest-different-from-catch&quot;&gt;differences&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It hasn&#x27;t been easy to decide; both are really similar. Below you can see some differences:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;diff&quot; class=&quot;language-diff &quot;&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;@@ -1,12 +1,12 @@
-#define CATCH_CONFIG_MAIN &amp;#x2F;&amp;#x2F; It tells Catch to provide a main() - only do this in one cpp file
+#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN

-#include &amp;quot;catch.hpp&amp;quot;
+#include &amp;quot;doctest.h&amp;quot;
#include &amp;quot;Uuid.h&amp;quot;
#include &amp;lt;string&amp;gt;

constexpr int MAX_ITERS = 100;

-TEST_CASE(&amp;quot;Uuid&amp;quot;, &amp;quot;[uuid]&amp;quot;)
+TEST_CASE(&amp;quot;Uuid&amp;quot;)
@@ -26,7 +26,7 @@ TEST_CASE(&amp;quot;Uuid&amp;quot;, &amp;quot;[uuid]&amp;quot;)
&amp;#x2F;&amp;#x2F; BDD style

-SCENARIO(&amp;quot;UUID creation&amp;quot;, &amp;quot;[Uuid]&amp;quot;)
+SCENARIO(&amp;quot;UUID creation&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I&#x27;ve finally chosen Doctest because it promises to be faster: &lt;a href=&quot;&#x2F;content&#x2F;blog&#x2F;serialization-java-serializable-externalizable.en.md&quot;&gt;performance results&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: I&#x27;ve created the project using both frameworks; you can find them in the corresponding branches: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&#x2F;tree&#x2F;doctest&quot;&gt;doctest branch&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&#x2F;tree&#x2F;catch&quot;&gt;catch branch&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve created an example to illustrate this article: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&quot;&gt;uuid-cpp&lt;&#x2F;a&gt;. It is a basic implementation of UUID pseudo-random generator based on &lt;a href=&quot;https:&#x2F;&#x2F;www.cplusplus.com&#x2F;reference&#x2F;random&#x2F;mt19937&quot;&gt;mt19937&lt;&#x2F;a&gt;, which is not cryptographically secure.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;project-output-artifacts&quot;&gt;Project output artifacts&lt;&#x2F;h3&gt;
&lt;p&gt;When we install the project using Meson (Ninja), we will get some artifacts generated and copied in our system:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Shared library: &lt;code&gt;libuuid&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Header library for developers who want to use the shared library: &lt;code&gt;include&#x2F;Uuid.h&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Executable &lt;code&gt;uuidgen&lt;&#x2F;code&gt; (&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Universally_unique_identifier&quot;&gt;UUID&lt;&#x2F;a&gt; generator).&lt;&#x2F;li&gt;
&lt;li&gt;Test executable (not installed). It tests the shared library.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For example, if you execute:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;#x2F;usr&amp;#x2F;local&amp;#x2F;lib&amp;#x2F;libuuid.so
&amp;#x2F;usr&amp;#x2F;local&amp;#x2F;include&amp;#x2F;Uuid.h
&amp;#x2F;usr&amp;#x2F;local&amp;#x2F;bin&amp;#x2F;uuidgen
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;project-structure-fork-project&quot;&gt;Project structure (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;uuid-cpp&quot;&gt;Fork project&lt;&#x2F;a&gt;)&lt;&#x2F;h3&gt;
&lt;p&gt;...existing code...&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Filesystem in C++17</title>
        <published>2017-05-28T00:00:00+00:00</published>
        <updated>2017-05-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/recursive-directory-iterator/"/>
        <id>https://carlosvin.github.io/recursive-directory-iterator/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/recursive-directory-iterator/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;Since C++17 new filesystem abstractions will be added to C++ environment. So far they are available as &lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;experimental&quot;&gt;Experimental C++ Features&lt;&#x2F;a&gt;. If you want to dig more about this new library, here it is the &lt;a href=&quot;http:&#x2F;&#x2F;www.open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2014&#x2F;n4100.pdf&quot;&gt;final draft of File System Technical Specification&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gettting-started-with-experimental-filesystem-features-c-17-g&quot;&gt;Gettting started with Experimental Filesystem Features C++17 (g++)&lt;&#x2F;h2&gt;
&lt;p&gt;We just have to &quot;tell&quot; compiler that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;we write C++17 (&lt;code&gt;-c++1z&lt;&#x2F;code&gt;) and&lt;&#x2F;li&gt;
&lt;li&gt;it has to add &lt;em&gt;standard library with filesystem library&lt;&#x2F;em&gt; (&lt;code&gt;-lstdc++fs&lt;&#x2F;code&gt;).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;g++ -std=c++1z main.cpp -lstdc++fs &amp;amp;&amp;amp; .&amp;#x2F;a.out
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s see a simple example with &lt;code&gt;std::filesystem::path&lt;&#x2F;code&gt; class.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;experimental&amp;#x2F;filesystem&amp;gt;
#include &amp;lt;iostream&amp;gt;

namespace fs = std::experimental::filesystem;
using namespace std;

int main()
{
    fs::path aPath {&amp;quot;.&amp;#x2F;path&amp;#x2F;to&amp;#x2F;file.txt&amp;quot;};

    cout &amp;lt;&amp;lt; &amp;quot;Parent path: &amp;quot; &amp;lt;&amp;lt; aPath.parent_path() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; &amp;quot;Filename: &amp;quot; &amp;lt;&amp;lt; aPath.filename() &amp;lt;&amp;lt; endl;
    cout &amp;lt;&amp;lt; &amp;quot;Extension: &amp;quot; &amp;lt;&amp;lt; aPath.extension() &amp;lt;&amp;lt; endl;

    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;compile-and-run-basic-c-17-example&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;9f8bebb8b7f0fbe7&quot;&gt;Compile and run: Basic C++17 example&lt;&#x2F;a&gt;&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ g++ -std=c++1z main.cpp -lstdc++fs &amp;amp;&amp;amp; .&amp;#x2F;a.out
$ .&amp;#x2F;a.out

Parent path: &amp;quot;.&amp;#x2F;path&amp;#x2F;to&amp;quot;
Filename: &amp;quot;file.txt&amp;quot;
Extension: &amp;quot;.txt&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;c-17-filesystem-features&quot;&gt;C++17 Filesystem Features&lt;&#x2F;h2&gt;
&lt;p&gt;In this section, we are going to explain some &lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;filesystem&quot;&gt;std::filesystem&lt;&#x2F;a&gt; features with examples, which will help us to highlight differences between C++11 and C++17 so we can get a better idea about what this new library will supply and how it might make developer&#x27;s work easier.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;std-filesystem-path&quot;&gt;std::filesystem::path&lt;&#x2F;h3&gt;
&lt;p&gt;Upper we have seen a tiny &lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;9f8bebb8b7f0fbe7&quot;&gt;use case for std::filesystem::path&lt;&#x2F;a&gt;. That is a quite powerful and convenient feature that supplies an multi-platform abstraction for paths to files using the correct directory path separator depending on the platform we are building our application for (&lt;code&gt;\&lt;&#x2F;code&gt; for Windows based systems and &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; for Unix based systems).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;directory-separator&quot;&gt;Directory separator&lt;&#x2F;h3&gt;
&lt;p&gt;When we want our application to use the correct directory separator in C++11, we could use conditional macro declaration:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;platform-independent-directory-separator-in-c-11&quot;&gt;Platform independent directory separator in C++11&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;

using namespace std;

#ifdef _WIN32
const string SEP = &amp;quot;\\&amp;quot;;
#else
const string SEP = &amp;quot;&amp;#x2F;&amp;quot;;
#endif

int main()
{
    cout &amp;lt;&amp;lt; &amp;quot;Separator in my system &amp;quot; &amp;lt;&amp;lt; SEP &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;5023ee989105fc54&quot;&gt;Compile and run: C++11 separator example&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;platform-independent-directory-separator-in-c-17-cleaner-and-simpler&quot;&gt;Platform independent directory separator in C++17. Cleaner and simpler&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;experimental&amp;#x2F;filesystem&amp;gt;
#include &amp;lt;iostream&amp;gt;

namespace fs = std::experimental::filesystem;
using namespace std;

int main()
{
    cout &amp;lt;&amp;lt; &amp;quot;Separator in my system &amp;quot; &amp;lt;&amp;lt; fs::path::preferred_separator &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;1f2f63b3f5597d05&quot;&gt;Compile and run: C++17 separator example&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;directory-separator-operator&quot;&gt;Directory Separator Operator&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;filesystem&#x2F;path&quot;&gt;std::filesystem::path&lt;&#x2F;a&gt; implements &lt;code&gt;&#x2F;&lt;&#x2F;code&gt; operator, which allows to easily concatenate paths to files and directories.&lt;&#x2F;p&gt;
&lt;p&gt;When we want to concatenate paths in C++11, we have to add extra logic to avoid adding duplicate separators and to select the correct separator for target platform:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;concatenate-paths-in-c-11&quot;&gt;Concatenate paths in C++11&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;

using namespace std;

#ifdef _WIN32
const string SEP = &amp;quot;\\&amp;quot;;
#else
const string SEP = &amp;quot;&amp;#x2F;&amp;quot;;
#endif

int main()
{
    string root {&amp;quot;&amp;#x2F;&amp;quot;};
    string dir {&amp;quot;var&amp;#x2F;www&amp;#x2F;&amp;quot;};
    string index {&amp;quot;index.html&amp;quot;};

    string pathToIndex{};
    pathToIndex.append(root).append(SEP).append(dir).append(SEP).append(index);

    cout &amp;lt;&amp;lt; pathToIndex &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-concatenate-paths-in-c-11&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;290b278ec1de9573&quot;&gt;Compile and run: Concatenate paths in C++11&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;#x2F;&amp;#x2F;var&amp;#x2F;www&amp;#x2F;&amp;#x2F;index.html
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Checking program output we notice it is not fully correct, we should have checked whether path parts already contains a separator so we don&#x27;t append another separator again. That logic is already implemented in &lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;filesystem&#x2F;path&quot;&gt;std::filesystem::path&lt;&#x2F;a&gt;, so C++17 can be like:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;concatenate-paths-in-c-17&quot;&gt;Concatenate paths in C++17&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;experimental&amp;#x2F;filesystem&amp;gt;
#include &amp;lt;iostream&amp;gt;

namespace fs = std::experimental::filesystem;
using namespace std;

int main()
{
    fs::path root {&amp;quot;&amp;#x2F;&amp;quot;};
    fs::path dir {&amp;quot;var&amp;#x2F;www&amp;#x2F;&amp;quot;};
    fs::path index {&amp;quot;index.html&amp;quot;};

    fs::path pathToIndex = root &amp;#x2F; dir &amp;#x2F; index;

    cout &amp;lt;&amp;lt; pathToIndex &amp;lt;&amp;lt; endl;
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-concatenate-paths-in-c-17&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;a24d50875b4daad1&quot;&gt;Compile and run: Concatenate paths in C++17&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;quot;&amp;#x2F;var&amp;#x2F;www&amp;#x2F;index.html&amp;quot;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Code is cleaner and just correct, there are no duplicated separators.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-remove-directories&quot;&gt;Create&#x2F;Remove Directories&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;filesystem&quot;&gt;std::filesystem&lt;&#x2F;a&gt; comes with some utilities to create and remove files and directories, but firstly let&#x27;s try to do so in C++11.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;create-and-remove-nested-directories-in-c-11&quot;&gt;Create and remove nested directories in C++11&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;sys&amp;#x2F;stat.h&amp;gt;

using namespace std;

int main()
{
    auto opts = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
    mkdir(&amp;quot;sandbox&amp;quot;, opts);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;quot;, opts);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;#x2F;b&amp;quot;, opts);
    mkdir(&amp;quot;sandbox&amp;#x2F;c&amp;quot;, opts);
    mkdir(&amp;quot;sandbox&amp;#x2F;c&amp;#x2F;d&amp;quot;, opts);

    system(&amp;quot;ls -la sandbox&amp;#x2F;*&amp;quot;);

    remove(&amp;quot;sandbox&amp;#x2F;c&amp;#x2F;d&amp;quot;);
    remove(&amp;quot;sandbox&amp;#x2F;a&amp;#x2F;b&amp;quot;);
    remove(&amp;quot;sandbox&amp;#x2F;c&amp;quot;);
    remove(&amp;quot;sandbox&amp;#x2F;a&amp;quot;);
    remove(&amp;quot;sandbox&amp;quot;);

    system(&amp;quot;ls -la&amp;quot;);

    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-create-and-remove-directories-c-11&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;26f4763ec5b42adb&quot;&gt;Compile and run: Create and remove directories C++11&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;g++-4.9 -std=c++11 main.cpp -lm &amp;amp;&amp;amp; .&amp;#x2F;a.out
sandbox&amp;#x2F;a:
total 12
drwxr-xr-x 3 2001 2000 4096 May 28 12:27 .
drwxr-xr-x 4 2001 2000 4096 May 28 12:27 ..
drwxr-xr-x 2 2001 2000 4096 May 28 12:27 b

sandbox&amp;#x2F;c:
total 12
drwxr-xr-x 3 2001 2000 4096 May 28 12:27 .
drwxr-xr-x 4 2001 2000 4096 May 28 12:27 ..
drwxr-xr-x 2 2001 2000 4096 May 28 12:27 d
total 8012
drwxrwxrwx 2 2001 2000    4096 May 28 12:27 .
drwxrwxrwx 3 2002 2000 8175616 May 28 12:27 ..
-rwxr-xr-x 1 2001 2000    8168 May 28 12:27 a.out
-rw-rw-rw- 1 2001 2000     517 May 28 12:27 main.cpp
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We have to create&#x2F;remove one by one. We could rewrite this code snippet with less lines (using a loop), but we still have to pay attention to creation&#x2F;deletion order, we cannot remove parent directory before we have removed all children.&lt;&#x2F;p&gt;
&lt;p&gt;Since C++17, we can create and remove nested directories with just one call.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;create-and-remove-nested-directories-c-17&quot;&gt;Create and remove nested directories C++17&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;experimental&amp;#x2F;filesystem&amp;gt;
#include &amp;lt;iostream&amp;gt;

namespace fs = std::experimental::filesystem;
using namespace std;

int main()
{
    fs::create_directories(&amp;quot;sandbox&amp;#x2F;a&amp;#x2F;b&amp;quot;);
    fs::create_directories(&amp;quot;sandbox&amp;#x2F;c&amp;#x2F;d&amp;quot;);
    system(&amp;quot;ls -la sandbox&amp;#x2F;*&amp;quot;);

    cout &amp;lt;&amp;lt; &amp;quot;Were directories removed? &amp;quot; &amp;lt;&amp;lt; fs::remove_all(&amp;quot;sandbox&amp;quot;) &amp;lt;&amp;lt; endl;
    system(&amp;quot;ls -la&amp;quot;);

    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-create-and-remove-nested-directories-c-17&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;62c2d22fa0e7144c&quot;&gt;Compile and run: Create and remove nested directories C++17&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;g++ -std=c++1z -fconcepts -fgnu-tm  -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm  -latomic -lstdc++fs &amp;amp;&amp;amp; .&amp;#x2F;a.out
sandbox&amp;#x2F;a:
total 12
drwxr-xr-x 3 2001 2000 4096 May 28 16:45 .
drwxr-xr-x 4 2001 2000 4096 May 28 16:45 ..
drwxr-xr-x 2 2001 2000 4096 May 28 16:45 b

sandbox&amp;#x2F;c:
total 12
drwxr-xr-x 3 2001 2000 4096 May 28 16:45 .
drwxr-xr-x 4 2001 2000 4096 May 28 16:45 ..
drwxr-xr-x 2 2001 2000 4096 May 28 16:45 d
Were directories removed? 1
total 10132
drwxrwxrwx 2 2001 2000    4096 May 28 16:45 .
drwxrwxrwx 3 2002 2000 8175616 May 28 16:45 ..
-rwxr-xr-x 1 2001 2000 2170976 May 28 16:45 a.out
-rw-rw-rw- 1 2001 2000     393 May 28 16:45 main.cpp
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;full-example-recursive-directory-iterator&quot;&gt;Full example: Recursive Directory Iterator&lt;&#x2F;h2&gt;
&lt;p&gt;This example consists of iterate recursively through dicrectories fintering files by extension.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;c-11&quot;&gt;C++11&lt;&#x2F;h3&gt;
&lt;p&gt;To keep C++11 example simple, I haven&#x27;t added filtering  logic, but filtering logic is present in C++17 example:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;filesystem-11-cpp&quot;&gt;filesystem.11.cpp&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;dirent.h&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;fstream&amp;gt; &amp;#x2F;&amp;#x2F; std::ofstream
#include &amp;lt;vector&amp;gt;
#include &amp;lt;memory&amp;gt;
#include &amp;lt;system_error&amp;gt;
#include &amp;lt;sys&amp;#x2F;stat.h&amp;gt;

using namespace std;

const string UP_DIR = &amp;quot;..&amp;quot;;
const string CURRENT_DIR = &amp;quot;.&amp;quot;;
const string SEP = &amp;quot;&amp;#x2F;&amp;quot;;


string path(initializer_list&amp;lt;string&amp;gt; parts) 
{
    string pathTmp {};
    string separator = &amp;quot;&amp;quot;;
    for (auto &amp;amp; part: parts) 
    {
        pathTmp.append(separator).append(part);
        separator = SEP;
    }
    return pathTmp;
}

vector&amp;lt;string&amp;gt; getDirectoryFiles(const string&amp;amp; dir, const vector&amp;lt;string&amp;gt; &amp;amp; extensions) 
{
    vector&amp;lt;string&amp;gt; files;
    shared_ptr&amp;lt;DIR&amp;gt; directory_ptr(opendir(dir.c_str()), [](DIR* dir){ dir &amp;amp;&amp;amp; closedir(dir); });
    if (!directory_ptr) 
    {
        throw system_error(error_code(errno, system_category()), &amp;quot;Error opening : &amp;quot; + dir);
    }
 
    struct dirent *dirent_ptr;
    while ((dirent_ptr = readdir(directory_ptr.get())) != nullptr) 
    {
        const string fileName {dirent_ptr-&amp;gt;d_name};
        if (dirent_ptr-&amp;gt;d_type == DT_DIR) 
        {
            if (CURRENT_DIR != fileName &amp;amp;&amp;amp; UP_DIR != fileName) 
            {
                auto subFiles = getDirectoryFiles(path({dir, fileName}), extensions);
                files.insert(end(files), begin(subFiles), end(subFiles));
            }
        } 
        else if (dirent_ptr-&amp;gt;d_type == DT_REG) 
        {
            &amp;#x2F;&amp;#x2F; here we should check also if filename has an extension in extensions vector
            files.push_back(path({dir, fileName}));
        }
    }
    return files;
}

int main ()
{
    auto opt = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
    mkdir(&amp;quot;sandbox&amp;quot;, opt);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;quot;, opt);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;#x2F;b&amp;quot;, opt);

 vector&amp;lt;string&amp;gt; e_files = {
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.rst&amp;quot;, 
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.txt&amp;quot;,
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;file2.RST&amp;quot;, 
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;file3.md&amp;quot;,
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;will_be.ignored&amp;quot;
 };
 
 &amp;#x2F;&amp;#x2F; create files
 for (auto &amp;amp;f: e_files)
 {
  ofstream of(f, ofstream::out);
  of &amp;lt;&amp;lt; &amp;quot;test&amp;quot;;
 }

    cout &amp;lt;&amp;lt; &amp;quot;filtered files: &amp;quot; &amp;lt;&amp;lt; endl;
 for (auto &amp;amp;f: getDirectoryFiles(&amp;quot;.&amp;quot;, {&amp;quot;.rst&amp;quot;, &amp;quot;.RST&amp;quot;, &amp;quot;.md&amp;quot;})){
     cout &amp;lt;&amp;lt; &amp;quot;\t&amp;quot; &amp;lt;&amp;lt; f &amp;lt;&amp;lt; endl;
 }

    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-c-11-example&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;af4228e039a281b3&quot;&gt;Compile and run C++11 example&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;g++ -std=c++11 -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm  -latomic -lstdc++fs &amp;amp;&amp;amp; .&amp;#x2F;a.out
filtered files: 
 .&amp;#x2F;main.cpp
 .&amp;#x2F;sandbox&amp;#x2F;file3.md
 .&amp;#x2F;sandbox&amp;#x2F;will_be.ignored
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.rst
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.txt
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;file2.RST
 .&amp;#x2F;a.out
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;c-17&quot;&gt;C++17&lt;&#x2F;h3&gt;
&lt;p&gt;Following example also filters files by extension.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;filesystem-17-cpp&quot;&gt;filesystem.17.cpp&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;#include &amp;lt;dirent.h&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;iostream&amp;gt;
#include &amp;lt;fstream&amp;gt; &amp;#x2F;&amp;#x2F; std::ofstream
#include &amp;lt;vector&amp;gt;
#include &amp;lt;memory&amp;gt;
#include &amp;lt;system_error&amp;gt;
#include &amp;lt;sys&amp;#x2F;stat.h&amp;gt;

using namespace std;

const string UP_DIR = &amp;quot;..&amp;quot;;
const string CURRENT_DIR = &amp;quot;.&amp;quot;;
const string SEP = &amp;quot;&amp;#x2F;&amp;quot;;


string path(initializer_list&amp;lt;string&amp;gt; parts) 
{
    string pathTmp {};
    string separator = &amp;quot;&amp;quot;;
    for (auto &amp;amp; part: parts) 
    {
        pathTmp.append(separator).append(part);
        separator = SEP;
    }
    return pathTmp;
}

vector&amp;lt;string&amp;gt; getDirectoryFiles(const string&amp;amp; dir, const vector&amp;lt;string&amp;gt; &amp;amp; extensions) 
{
    vector&amp;lt;string&amp;gt; files;
    shared_ptr&amp;lt;DIR&amp;gt; directory_ptr(opendir(dir.c_str()), [](DIR* dir){ dir &amp;amp;&amp;amp; closedir(dir); });
    if (!directory_ptr) 
    {
        throw system_error(error_code(errno, system_category()), &amp;quot;Error opening : &amp;quot; + dir);
    }
 
    struct dirent *dirent_ptr;
    while ((dirent_ptr = readdir(directory_ptr.get())) != nullptr) 
    {
        const string fileName {dirent_ptr-&amp;gt;d_name};
        if (dirent_ptr-&amp;gt;d_type == DT_DIR) 
        {
            if (CURRENT_DIR != fileName &amp;amp;&amp;amp; UP_DIR != fileName) 
            {
                auto subFiles = getDirectoryFiles(path({dir, fileName}), extensions);
                files.insert(end(files), begin(subFiles), end(subFiles));
            }
        } 
        else if (dirent_ptr-&amp;gt;d_type == DT_REG) 
        {
            &amp;#x2F;&amp;#x2F; here we should check also if filename has an extension in extensions vector
            files.push_back(path({dir, fileName}));
        }
    }
    return files;
}

int main ()
{
    auto opt = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
    mkdir(&amp;quot;sandbox&amp;quot;, opt);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;quot;, opt);
    mkdir(&amp;quot;sandbox&amp;#x2F;a&amp;#x2F;b&amp;quot;, opt);

 vector&amp;lt;string&amp;gt; e_files = {
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.rst&amp;quot;, 
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.txt&amp;quot;,
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;file2.RST&amp;quot;, 
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;file3.md&amp;quot;,
     &amp;quot;.&amp;#x2F;sandbox&amp;#x2F;will_be.ignored&amp;quot;
 };
 
 &amp;#x2F;&amp;#x2F; create files
 for (auto &amp;amp;f: e_files)
 {
  ofstream of(f, ofstream::out);
  of &amp;lt;&amp;lt; &amp;quot;test&amp;quot;;
 }

    cout &amp;lt;&amp;lt; &amp;quot;filtered files: &amp;quot; &amp;lt;&amp;lt; endl;
 for (auto &amp;amp;f: getDirectoryFiles(&amp;quot;.&amp;quot;, {&amp;quot;.rst&amp;quot;, &amp;quot;.RST&amp;quot;, &amp;quot;.md&amp;quot;})){
     cout &amp;lt;&amp;lt; &amp;quot;\t&amp;quot; &amp;lt;&amp;lt; f &amp;lt;&amp;lt; endl;
 }

    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;compile-and-run-c-17-example&quot;&gt;&lt;a href=&quot;https:&#x2F;&#x2F;coliru.stacked-crooked.com&#x2F;a&#x2F;af4228e039a281b3&quot;&gt;Compile and run C++17 example&lt;&#x2F;a&gt;&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;g++ -std=c++11 -O2 -Wall -Wextra -pedantic -pthread -pedantic-errors main.cpp -lm  -latomic -lstdc++fs &amp;amp;&amp;amp; .&amp;#x2F;a.out
filtered files: 
 .&amp;#x2F;main.cpp
 .&amp;#x2F;sandbox&amp;#x2F;file3.md
 .&amp;#x2F;sandbox&amp;#x2F;will_be.ignored
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.rst
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;b&amp;#x2F;file1.txt
 .&amp;#x2F;sandbox&amp;#x2F;a&amp;#x2F;file2.RST
 .&amp;#x2F;a.out
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Multi-Domain Docker Containers</title>
        <published>2016-11-24T00:00:00+00:00</published>
        <updated>2016-11-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/reverse-proxy-multidomain-docker/"/>
        <id>https://carlosvin.github.io/reverse-proxy-multidomain-docker/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/reverse-proxy-multidomain-docker/">&lt;h2 id=&quot;use-case&quot;&gt;Use case&lt;&#x2F;h2&gt;
&lt;p&gt;We have several server applications in the same development environment, each application is bundled in a Docker container, e.g: &lt;strong&gt;&quot;Container A&quot;&lt;&#x2F;strong&gt; and &lt;strong&gt;&quot;Container B&quot;&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;With Docker those applications have the same IP address. One way to differentiate and access to an specific application is exposing different ports.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;reverse-proxy-multidomain-docker&#x2F;ip.png&quot; alt=&quot;Containers exposing the same IP address and different ports.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If we want to call to &lt;strong&gt;&quot;Application A&quot;&lt;&#x2F;strong&gt; we will do: &lt;code&gt;GET http:&#x2F;&#x2F;10.20.30.40:8080&#x2F;colors&#x2F;red&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;If we want to call to &lt;strong&gt;&quot;Application B&quot;&lt;&#x2F;strong&gt; we will do: &lt;code&gt;GET http:&#x2F;&#x2F;10.20.30.40:8081&#x2F;fruits&#x2F;tomato&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But that solution is a little bit confusing, does 8080 mean we are accessing to &quot;application A&quot;?&lt;&#x2F;p&gt;
&lt;p&gt;It would be &lt;strong&gt;simpler and easier&lt;&#x2F;strong&gt; to remind something like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Calling &lt;strong&gt;&quot;Application A&quot;&lt;&#x2F;strong&gt;: &lt;code&gt;GET http:&#x2F;&#x2F;a.domain.com&#x2F;colors&#x2F;red&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Calling &lt;strong&gt;&quot;Application B&quot;&lt;&#x2F;strong&gt;: &lt;code&gt;GET http:&#x2F;&#x2F;b.domain.com&#x2F;fruits&#x2F;tomato&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;reverse-proxy-multidomain-docker&#x2F;domain.png&quot; alt=&quot;Accessing applications by domain name.&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Get that extra semantic value is much simpler than I thought at the beginning and you will see below.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-configure-multi-domain-reverse-proxy&quot;&gt;How to Configure Multi-Domain Reverse Proxy&lt;&#x2F;h2&gt;
&lt;p&gt;I said it is easy, because we almost have to do nothing, another container will do it for us, especifically we are going to use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jwilder&#x2F;nginx-proxy&quot;&gt;nginx-proxy&lt;&#x2F;a&gt;, it will automatically generate the required &lt;a href=&quot;https:&#x2F;&#x2F;www.nginx.com&quot;&gt;NGINX&lt;&#x2F;a&gt; configurations.&lt;&#x2F;p&gt;
&lt;p&gt;So, we will have 2 applications + 1 proxy, that is 3 containers.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;reverse-proxy-multidomain-docker&#x2F;proxy.png&quot; alt=&quot;3 containers, 2 applications and 1 proxy&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: You can download the full example at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;docker-reverse-proxy-multi-domain&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;docker-reverse-proxy-multi-domain&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;example-project-structure&quot;&gt;Example Project Structure&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;docker-compose.yaml&lt;&#x2F;strong&gt;: Main configuration file describing architecture in previous picture.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;a&lt;&#x2F;strong&gt;: Application A directory.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dockerfile&lt;&#x2F;strong&gt;: Container A configuration file.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;b&lt;&#x2F;strong&gt;: Application B directory.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dockerfile&lt;&#x2F;strong&gt;: Container B configuration file.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;docker-reverse-proxy-multi-domain&quot;&gt;View Project&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;architecture-configuration-docker-compose&quot;&gt;Architecture Configuration (docker-compose)&lt;&#x2F;h3&gt;
&lt;p&gt;The relationships between containers is the most interesting part in this example.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;docker-reverse-proxy-multi-domain-docker-compose-yaml&quot;&gt;docker-reverse-proxy-multi-domain&#x2F;docker-compose.yaml&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;yaml&quot; class=&quot;language-yaml &quot;&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;a:
  build: a                # (4)
  environment:
    VIRTUAL_HOST: a.domain.com    # (1)
  restart: always

b:
  build: b                # (5)
  environment:
    VIRTUAL_HOST:  b.domain.com   # (2)
  restart: always

nginx-proxy:              # (3)
  image: jwilder&amp;#x2F;nginx-proxy
  ports:
    - &amp;quot;80:80&amp;quot;
    - &amp;quot;443:443&amp;quot;
  volumes:
    - &amp;#x2F;var&amp;#x2F;run&amp;#x2F;docker.sock:&amp;#x2F;tmp&amp;#x2F;docker.sock:ro

  restart: always
  privileged: true
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;Configure the domain name for app a.&lt;&#x2F;li&gt;
&lt;li&gt;Configure the domain name for app b.&lt;&#x2F;li&gt;
&lt;li&gt;From this line there is proxy configuration (copy&#x2F;paste part).&lt;&#x2F;li&gt;
&lt;li&gt;We tell docker-compose has to build Docker images within specified directory.&lt;&#x2F;li&gt;
&lt;li&gt;For example, we are saying that docker-compose has to build a Docker image using ..&#x2F;b&#x2F;Dockerfile file.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;application-image-configuration&quot;&gt;Application Image Configuration&lt;&#x2F;h3&gt;
&lt;h3 id=&quot;a-dockerfile&quot;&gt;a&#x2F;Dockerfile&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile &quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;FROM httpd:2.4                       # (1)
RUN echo &amp;quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;A&amp;lt;&amp;#x2F;h1&amp;gt;App A works!&amp;lt;&amp;#x2F;body&amp;gt;&amp;lt;&amp;#x2F;html&amp;gt;&amp;quot; &amp;gt; &amp;#x2F;usr&amp;#x2F;local&amp;#x2F;apache2&amp;#x2F;htdocs&amp;#x2F;index.html  # (2)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We import an image with an apache server.&lt;&#x2F;li&gt;
&lt;li&gt;It serves a file that prints &quot;Host A&quot; as default page.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The configuration for application B is pretty much the same:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;b-dockerfile&quot;&gt;b&#x2F;Dockerfile&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile &quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;FROM httpd:2.4
RUN echo &amp;quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;B&amp;lt;&amp;#x2F;h1&amp;gt;App B works!&amp;lt;&amp;#x2F;body&amp;gt;&amp;lt;&amp;#x2F;html&amp;gt;&amp;quot; &amp;gt; &amp;#x2F;usr&amp;#x2F;local&amp;#x2F;apache2&amp;#x2F;htdocs&amp;#x2F;index.html
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;adding-domain-names-to-your-development-environment-configuration&quot;&gt;Adding domain names to your development environment configuration&lt;&#x2F;h3&gt;
&lt;p&gt;In Linux we just have to map the local address to domain names you have chosen, in the example &lt;code&gt;a.domain.com&lt;&#x2F;code&gt; and &lt;code&gt;b.domain.com&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;etc-hosts&quot;&gt;&#x2F;etc&#x2F;hosts&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;127.0.0.1    localhost.localdomain localhost
::1          localhost6.localdomain6 localhost6
127.0.0.1    a.domain.com         # (1)
127.0.0.1    b.domain.com
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We just added last 2 lines.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;everything-ready&quot;&gt;Everything ready&lt;&#x2F;h3&gt;
&lt;p&gt;Now we just have to test the example:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;docker-compose build
docker-compose up
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The 3 containers are running now.&lt;&#x2F;p&gt;
&lt;p&gt;So we can open our favorite web browser and go to &lt;code&gt;a.domain.com&lt;&#x2F;code&gt;. It will show &lt;strong&gt;App A works!&lt;&#x2F;strong&gt;. If we go to &lt;code&gt;b.domain.com&lt;&#x2F;code&gt; then we will see &lt;strong&gt;App B works!&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;reverse-proxy-multidomain-docker&#x2F;a.screenshot.png&quot; alt=&quot;App A works!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;reverse-proxy-multidomain-docker&#x2F;b.screenshot.png&quot; alt=&quot;App B works!&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;&#x2F;strong&gt;: In most of the Linux distros you will need privileges to run Docker commands (&lt;code&gt;sudo&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Convert files formats - Windows to Unix</title>
        <published>2016-02-12T00:00:00+00:00</published>
        <updated>2016-02-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/recursive-dos-unix/"/>
        <id>https://carlosvin.github.io/recursive-dos-unix/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/recursive-dos-unix/">&lt;p&gt;If you are developing from a Windows environment to a Unix target environment, most likely you have had this issue: You install source files in Windows format in your Unix environment.&lt;&#x2F;p&gt;
&lt;p&gt;Windows and Unix systems use different line endings: Windows uses carriage return and line feed (&lt;code&gt;\r\n&lt;&#x2F;code&gt;), while Unix uses just line feed (&lt;code&gt;\n&lt;&#x2F;code&gt;). This difference can cause issues with scripts, code, and configuration files when moving files between systems.&lt;&#x2F;p&gt;
&lt;p&gt;There is a quite simple way to convert all your files from Windows to Unix format:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;find . -type f -print0 | xargs -0 dos2unix
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I got it, of course, from &lt;a href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;11929461&#x2F;how-can-i-run-dos2unix-on-an-entire-directory&quot;&gt;this Stack Overflow answer&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>REST URLs</title>
        <published>2015-08-16T00:00:00+00:00</published>
        <updated>2015-08-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/rest-urls/"/>
        <id>https://carlosvin.github.io/rest-urls/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/rest-urls/">&lt;p&gt;First time I designed a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; I made several mistakes, of course. Following I&#x27;m going to explain common mistakes and what I&#x27;ve learned about &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uniform_resource_locator&quot;&gt;URL&lt;&#x2F;a&gt; with examples.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rest-basics&quot;&gt;REST Basics&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uniform_resource_locator&quot;&gt;URL&lt;&#x2F;a&gt;s for get resources.&lt;&#x2F;li&gt;
&lt;li&gt;Using &lt;em&gt;verbs&lt;&#x2F;em&gt; for modify resources.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;em&gt;verbs&lt;&#x2F;em&gt; are provided by the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; protocol.&lt;&#x2F;li&gt;
&lt;li&gt;The &lt;em&gt;verbs&lt;&#x2F;em&gt; have a direct equivalency with &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;CRUD&quot;&gt;CRUD&lt;&#x2F;a&gt; (Create, Read, Update, Delete).&lt;&#x2F;li&gt;
&lt;li&gt;To access to an existent resource we need an identifier.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;rest-verbs&quot;&gt;REST Verbs&lt;&#x2F;h3&gt;
&lt;p&gt;POST: &lt;strong&gt;Create&lt;&#x2F;strong&gt; new resources.&lt;br &#x2F;&gt;
GET: &lt;strong&gt;Read&lt;&#x2F;strong&gt; already existing resources.&lt;br &#x2F;&gt;
PUT: &lt;strong&gt;Update&lt;&#x2F;strong&gt; already existing resources.&lt;br &#x2F;&gt;
DELETE: &lt;strong&gt;Delete&lt;&#x2F;strong&gt; already existing resources.&lt;&#x2F;p&gt;
&lt;p&gt;It is clearer in the following table:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;REST Verb&lt;&#x2F;th&gt;&lt;th&gt;CRUD Action&lt;&#x2F;th&gt;&lt;th&gt;Resource must exist&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;POST&lt;&#x2F;td&gt;&lt;td&gt;Create&lt;&#x2F;td&gt;&lt;td&gt;No&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;GET&lt;&#x2F;td&gt;&lt;td&gt;Read&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;PUT&lt;&#x2F;td&gt;&lt;td&gt;Update&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;DELETE&lt;&#x2F;td&gt;&lt;td&gt;Delete&lt;&#x2F;td&gt;&lt;td&gt;Yes&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;accessing-to-resources&quot;&gt;Accessing to Resources&lt;&#x2F;h3&gt;
&lt;p&gt;A resource is &lt;em&gt;what we want to get&lt;&#x2F;em&gt;. For example, a car.&lt;&#x2F;p&gt;
&lt;p&gt;To be able to get a car, that information is not enough, you can&#x27;t go to your car dealer and ask for whatever car, you have to specify which one you want:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good morning. I&#x27;d like to have a Fiat Bravo 1.9 Emotion 120CV.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In this manner the seller knows which one is.&lt;&#x2F;p&gt;
&lt;p&gt;&quot;Fiat Bravo 1.9 Emotion 120CV&quot; is the &lt;strong&gt;identifier&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Transferring the example to &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt;s:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;fiat-bravo-19-emotion-120cv
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now our &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; can supply the car info.&lt;&#x2F;p&gt;
&lt;p&gt;This is a very simple example, but actually when we access to a specific resource, we have to use something to identify it, a common and recommendable practice is use &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Universally_unique_identifier&quot;&gt;UUID&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET  https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But our &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt;, like a shop, it hasn&#x27;t to be so strict. We can ask for cars with several features:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Good morning, I want a Fiat Bravo.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Then, the dealer kindly will show you all Fiat Bravo he has available. Let&#x27;s see how &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; says that.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET  https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;?brand=fiat&amp;amp;model=bravo
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; will return all cars with Fiat brand and Bravo model.&lt;&#x2F;p&gt;
&lt;p&gt;Brand and model are so called &lt;strong&gt;query parameters&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As you might already notice, to get resource information, we have always used &lt;strong&gt;GET&lt;&#x2F;strong&gt; &lt;em&gt;verb&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;update-resources&quot;&gt;Update resources&lt;&#x2F;h3&gt;
&lt;p&gt;The &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; should also support updating resources. Like reading resources, to update a resource we have to specify which resource we want to update, so we again need an &lt;em&gt;identifier&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Before, we wanted to get information (read) and we used &lt;strong&gt;GET&lt;&#x2F;strong&gt; &lt;em&gt;verb&lt;&#x2F;em&gt;. Now the only difference is the verb.&lt;&#x2F;p&gt;
&lt;p&gt;We want to &lt;strong&gt;update&lt;&#x2F;strong&gt; so we use the equivalency &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; verb: &lt;strong&gt;PUT&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;PUT   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Actually something else is missing, we have to say what thing of the car we want to change, for example, let&#x27;s imagine we want to change the engine power and set it to 100CV.&lt;&#x2F;p&gt;
&lt;p&gt;We have to send the new engine power to following &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uniform_resource_locator&quot;&gt;URL&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;cardealer.com&#x2F;api&#x2F;cars&#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&quot;&gt;https:&#x2F;&#x2F;cardealer.com&#x2F;api&#x2F;cars&#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;a&gt; through &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; using &lt;strong&gt;PUT&lt;&#x2F;strong&gt; verb.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; protocol allows sending data within PUT message, we have to choose a sending format.&lt;&#x2F;p&gt;
&lt;p&gt;We can use &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;JSON&quot;&gt;JSON&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;XML&quot;&gt;XML&lt;&#x2F;a&gt; or whatever, we only have to ensure that sent format is expected in server side.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; Designing a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; requires to select a data format.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;strong&gt;JSON example:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{ &amp;quot;enginePower&amp;quot;: 100 }
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;delete-resources&quot;&gt;Delete Resources&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s imagine that now we are the car dealer and we don&#x27;t want to sell the Fiat Bravo Emotion 1.9CV anymore (the cce05bee-386b-11e5-a151-feff819cdc9f). We&#x27;ll keep the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uniform_resource_locator&quot;&gt;URL&lt;&#x2F;a&gt; that identifies the resource, but we change the verb: we don&#x27;t want to read (GET), we don&#x27;t want to update (PUT), we want to &lt;strong&gt;delete (DELETE)&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;DELETE   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We don&#x27;t have to supply any additional info, only the verb (DELETE) and the resource identifier.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;create-resources&quot;&gt;Create Resources&lt;&#x2F;h3&gt;
&lt;p&gt;And the last verb is &lt;strong&gt;create (POST)&lt;&#x2F;strong&gt;. In this case we don&#x27;t have to identify the resource, because it still doesn&#x27;t exist.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;POST   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But we have to send the data to create the resource.&lt;&#x2F;p&gt;
&lt;p&gt;Following with the example, let&#x27;s create a new car, so we include the necessary data within POST &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; message, it is something similar what we did at section &quot;Update resources&quot;, but we are going to send &lt;strong&gt;all required data&lt;&#x2F;strong&gt;, not only the engine power.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;JSON example:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;brand&amp;quot;: &amp;quot;Fiat&amp;quot;,
  &amp;quot;model&amp;quot;: &amp;quot;Bravo&amp;quot;,
  &amp;quot;year&amp;quot;: 2010,
  &amp;quot;doors&amp;quot;: 5,
  &amp;quot;enginePower&amp;quot;: 120,
  &amp;quot;version&amp;quot;: &amp;quot;Emotion&amp;quot;,
  &amp;quot;clima&amp;quot;: true,
  &amp;quot;ac&amp;quot;: false,
  &amp;quot;fuel&amp;quot;: &amp;quot;Diesel&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can delegate on the system to assign a new &lt;strong&gt;identifier&lt;&#x2F;strong&gt;, or simply send it within the message:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;identifier&amp;quot;: &amp;quot;cce05bee-386b-11e5-a151-feff819cdc9f&amp;quot;,
  &amp;quot;brand&amp;quot;: &amp;quot;Fiat&amp;quot;,
  &amp;quot;model&amp;quot;: &amp;quot;Bravo&amp;quot;,
  &amp;quot;year&amp;quot;: 2010,
  &amp;quot;doors&amp;quot;: 5,
  &amp;quot;enginePower&amp;quot;: 120,
  &amp;quot;version&amp;quot;: &amp;quot;Emotion&amp;quot;,
  &amp;quot;clima&amp;quot;: true,
  &amp;quot;ac&amp;quot;: false,
  &amp;quot;fuel&amp;quot;: &amp;quot;Diesel&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;collections&quot;&gt;Collections&lt;&#x2F;h3&gt;
&lt;p&gt;All actions we have already explained were actually applied over a cars collection.&lt;&#x2F;p&gt;
&lt;p&gt;But, what happens if a resource has a nested collection?&lt;&#x2F;p&gt;
&lt;p&gt;Continuing with cars example, a car can use a set of engine oils. So the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; must allow update, delete or create elements in the set.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; For the example we will assume that &lt;em&gt;the oil identifier&lt;&#x2F;em&gt; is the attribute &lt;em&gt;type&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h4 id=&quot;add-an-element-to-collection&quot;&gt;Add an element to collection&lt;&#x2F;h4&gt;
&lt;p&gt;When we add a car to cars collection, what we do is create a new car, so it is the case of &quot;Create Resources&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;To add a new engine oil to the car cce05bee-386b-11e5-a151-feff819cdc9f, that already exists:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;POST   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Response:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;type&amp;quot;: &amp;quot;5W30&amp;quot;,
  &amp;quot;otherInfo&amp;quot;: &amp;quot;This is the best oil for this car&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we want to add another one:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;POST   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Response:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;type&amp;quot;: &amp;quot;10W30&amp;quot;,
  &amp;quot;otherInfo&amp;quot;: &amp;quot;This is very good for cold weather&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;update-a-collection-item&quot;&gt;Update a collection item&lt;&#x2F;h4&gt;
&lt;p&gt;If we want to update the info of oil &lt;em&gt;5W30&lt;&#x2F;em&gt; of car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;PUT   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;5W30&amp;#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Response:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;{
  &amp;quot;type&amp;quot;: &amp;quot;5W30&amp;quot;,
  &amp;quot;otherInfo&amp;quot;: &amp;quot;This is no longer the best oil for this car&amp;quot;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;delete-a-collection-item&quot;&gt;Delete a collection item&lt;&#x2F;h4&gt;
&lt;p&gt;To delete an oil &lt;em&gt;10W30&lt;&#x2F;em&gt; from car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;DELETE   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;10W30
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;read-a-collection-item&quot;&gt;Read a collection item&lt;&#x2F;h4&gt;
&lt;p&gt;To get the oil info &lt;em&gt;10W30&lt;&#x2F;em&gt; of the car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;10W30
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;list-collection-items&quot;&gt;List collection items&lt;&#x2F;h4&gt;
&lt;p&gt;As we have seen at &quot;Read a collection item&quot;, we can get the info of every collection element, but we also can get multiple collection elements, sorted, paged and apply typical collection actions.&lt;&#x2F;p&gt;
&lt;p&gt;We can get all supported oils for a car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt;, it is as simple as:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can also get sorted items:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;?sort_by=type&amp;amp;order=asc
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can ask &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; to return the first 10 oils for car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;?number_of_elements=10
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; can support also pagination:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;?page=3&amp;amp;number_of_elements=2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Above request is telling &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; that returns the page 3 of all oils of car &lt;em&gt;cce05bee-386b-11e5-a151-feff819cdc9f&lt;&#x2F;em&gt; and it has to show 2 oils per page. If we want to go to next page:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Request:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;GET   https:&amp;#x2F;&amp;#x2F;cardealer.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;cce05bee-386b-11e5-a151-feff819cdc9f&amp;#x2F;oils&amp;#x2F;?page=4&amp;amp;number_of_elements=2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;All those features are supported by &lt;strong&gt;query parameters&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;common-mistake&quot;&gt;Common mistake&lt;&#x2F;h2&gt;
&lt;p&gt;First time I tried to design a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt; &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt; I designed an &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Application_programming_interface&quot;&gt;API&lt;&#x2F;a&gt;, but not &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Representational_state_transfer&quot;&gt;REST&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My main mistake was the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Uniform_resource_locator&quot;&gt;URL&lt;&#x2F;a&gt;s design, I added my own &lt;em&gt;verbs&lt;&#x2F;em&gt; skipping &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Hypertext_Transfer_Protocol&quot;&gt;HTTP&lt;&#x2F;a&gt; &lt;em&gt;verbs&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Wrong:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;POST    https:&amp;#x2F;&amp;#x2F;example.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;ford-focus&amp;#x2F;delete-oil&amp;#x2F;5W30
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;The correct way:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;DELETE  https:&amp;#x2F;&amp;#x2F;example.com&amp;#x2F;api&amp;#x2F;cars&amp;#x2F;ford-focus&amp;#x2F;oils&amp;#x2F;5W30
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Build C++ project with Gradle</title>
        <published>2014-09-27T00:00:00+00:00</published>
        <updated>2014-09-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/gradle-cpp/"/>
        <id>https://carlosvin.github.io/gradle-cpp/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/gradle-cpp/">&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h2&gt;
&lt;p&gt;I am more and more worried about building, dependency management and distribution of my projects. I&#x27;d like to find a tool that unifies those processes with independence of the language. I know several tools which almost fit to what I&#x27;m looking for, like &lt;a href=&quot;https:&#x2F;&#x2F;www.scons.org&quot;&gt;SCons&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;automake&#x2F;manual&#x2F;html_node&#x2F;Autotools-Introduction.html#Autotools-Introduction&quot;&gt;Autotools&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;ant.apache.org&quot;&gt;Ant&lt;&#x2F;a&gt;, &lt;a href=&quot;https:&#x2F;&#x2F;maven.apache.org&quot;&gt;Maven&lt;&#x2F;a&gt; and lately &lt;a href=&quot;https:&#x2F;&#x2F;www.gradle.org&quot;&gt;Gradle&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve made several projects with Gradle, but always they were &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;build&quot;&gt;Android&lt;&#x2F;a&gt; projects. &lt;del&gt;In Java projects I&#x27;ve found a Maven replacement, because it is faster, easier and less verbose&lt;&#x2F;del&gt;. &lt;strong&gt;Update 2020&lt;&#x2F;strong&gt;: With the experience, now if I have to pick a build system for a Java project I&#x27;d pick Maven, especially for a professional project, but it is not the topic of this post.&lt;&#x2F;p&gt;
&lt;p&gt;About Android projects I suffered the early adoption of &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;sdk&#x2F;installing&#x2F;studio-build.html&quot;&gt;Android Studio + Gradle&lt;&#x2F;a&gt;, although currently I think they are more mature and they work fine.&lt;&#x2F;p&gt;
&lt;p&gt;First of all, I have to say: building C&#x2F;C++&#x2F;Objective-C projects with Gradle is in &lt;a href=&quot;https:&#x2F;&#x2F;docs.gradle.org&#x2F;current&#x2F;userguide&#x2F;feature_lifecycle.html#sec:incubating_state&quot;&gt;incubation&lt;&#x2F;a&gt; phase, although now we can perform advanced tasks like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Generation several artifacts within same project (libraries and executables).&lt;&#x2F;li&gt;
&lt;li&gt;Dependency management between artifacts (no versions).&lt;&#x2F;li&gt;
&lt;li&gt;Different &quot;flavors&quot; of the same software, e.g: we can generate a &quot;Community&quot; release and other one with more enabled features called &quot;Enterprise&quot;.&lt;&#x2F;li&gt;
&lt;li&gt;It allows multi-platform binary generation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As I said, this plugin is still having limitations although they are working on it: &lt;a href=&quot;https:&#x2F;&#x2F;blog.gradle.org&#x2F;state-and-future-of-the-gradle-software-model#a-way-forward&quot;&gt;Gradle C++ roadmap&lt;&#x2F;a&gt;. &lt;del&gt;If they achieve it I&#x27;ll leave Autotools (I&#x27;m going to regret saying that)&lt;&#x2F;del&gt;. &lt;strong&gt;Update 2020&lt;&#x2F;strong&gt;: Actually few years later I am not using Autotools, neither Gradle, but I am using &lt;a href=&quot;https:&#x2F;&#x2F;mesonbuild.com&#x2F;&quot;&gt;Meson&lt;&#x2F;a&gt; and considering &lt;a href=&quot;https:&#x2F;&#x2F;docs.bazel.build&#x2F;versions&#x2F;master&#x2F;tutorial&#x2F;cpp.html&quot;&gt;Bazel&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;case-study&quot;&gt;Case study&lt;&#x2F;h2&gt;
&lt;p&gt;I&#x27;ve extracted all the case study from &lt;a href=&quot;https:&#x2F;&#x2F;docs.gradle.org&#x2F;current&#x2F;userguide&#x2F;native_software.html&quot;&gt;Gradle user guide for native software&lt;&#x2F;a&gt;. I&#x27;ve adapted the project to be multi-platform with 2 versions &quot;Community&quot; and &quot;Enterprise&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;The application consists of an executable and a dynamic library. The executable will use the library.&lt;&#x2F;p&gt;
&lt;p&gt;Gradle also is able to generate a distributable version and a debug version.&lt;&#x2F;p&gt;
&lt;p&gt;You can fork the code on &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;project-structure&quot;&gt;Project Structure&lt;&#x2F;h3&gt;
&lt;p&gt;We can create whichever directory structure, but it is easier using the proposed by Gradle, if not we&#x27;ll have to specify where the code is located.&lt;&#x2F;p&gt;
&lt;p&gt;This is the project structure:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;gradle-cpp: Root directory.
&lt;ul&gt;
&lt;li&gt;build.gradle: File where is configured Gradle project, it is the equivalent to: build.xml for Ant, &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;manual&#x2F;html_node&#x2F;Makefiles.html&quot;&gt;Makefile&lt;&#x2F;a&gt; for C&#x2F;C++ or pom.xml for Maven.&lt;&#x2F;li&gt;
&lt;li&gt;src: Folder where the source code is located.
&lt;ul&gt;
&lt;li&gt;hello: This folder contains the module hello. This module will generate hello library.
&lt;ul&gt;
&lt;li&gt;cpp: This folder contains C++ source files.
&lt;ul&gt;
&lt;li&gt;Hello.cpp:  File with the implementation of Hello class.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;headers: Folder with header files.
&lt;ul&gt;
&lt;li&gt;Hello.h: Class Hello declaration.&lt;&#x2F;li&gt;
&lt;li&gt;Msg.h: File with constants declarations.  &lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;main: This folder contains the module which produces the executable that uses hello library.
&lt;ul&gt;
&lt;li&gt;cpp: This folder contains C++ source files.
&lt;ul&gt;
&lt;li&gt;main.cpp: Source code of main function.  &lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;build: Folder created automatically by Gradle where it leaves all execution results like unit tests reports, compiled files, package distributions, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;c-application&quot;&gt;C++ Application&lt;&#x2F;h3&gt;
&lt;p&gt;It consists of an executable that uses the functionality implemented at &lt;code&gt;hello&lt;&#x2F;code&gt; library.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;main-cpp&quot;&gt;main.cpp&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;quot;Hello.h&amp;quot;
int main(int argc, char ** argv)
{
    Hello hello (&amp;quot;Pepito&amp;quot;);
    hello.sayHello(10);
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;hello&lt;&#x2F;code&gt; library allows greet &lt;code&gt;n&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#n&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; times to someone who is passed as argument to constructor class.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;n&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&#x27;n&#x27; Positive integer&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;hello-h&quot;&gt;Hello.h&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;class Hello
{
    private:
        const char * who;
    public:
        Hello(const char * who);
        void sayHello(unsigned n = 1);
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;building-with-gradle&quot;&gt;Building with Gradle&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;base-case&quot;&gt;Base case&lt;&#x2F;h4&gt;
&lt;p&gt;The only we need to build the application with Gradle is: having Gradle&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#wrapper&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and the file &lt;code&gt;build.gradle&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;wrapper&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;Actually Gradle is not required if we use the &quot;wrapper&quot;, but we aren&#x27;t going to explain it here, &lt;a href=&quot;https:&#x2F;&#x2F;docs.gradle.org&#x2F;current&#x2F;userguide&#x2F;gradle_wrapper.html&quot;&gt;here you can get more info about Gradle Wrapper&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;build-gradle-base-case&quot;&gt;build.gradle (Base Case)&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;groovy&quot; class=&quot;language-groovy &quot;&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;apply plugin: &amp;#x27;cpp&amp;#x27;

model {
  components {
    hello(NativeLibrarySpec) {}
    main(NativeExecutableSpec) {
      binaries.all {
        lib library: &amp;quot;hello&amp;quot;
      }
    }
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this simple file, we&#x27;ll be able to compile and install the application in Debug mode for the platform where we are executing Gradle (in my case X64).&lt;&#x2F;p&gt;
&lt;p&gt;If we execute &lt;code&gt;gradle task&lt;&#x2F;code&gt; from the root of the project, we&#x27;ll get all the tasks we can do with Gradle.&lt;&#x2F;p&gt;
&lt;p&gt;In our case, we just want our compiled application ready to run, so we have to execute: &lt;code&gt;gradle installMainExecutable&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Once execution has finished, we can run the program calling to &lt;code&gt;build&#x2F;install&#x2F;mainExecutable&#x2F;main&lt;&#x2F;code&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#bat&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;bat&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;.bat in Windows. Without extension in Linux.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;output&quot;&gt;Output&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ build&amp;#x2F;install&amp;#x2F;mainExecutable&amp;#x2F;main
1.  Hello Mr. Pepito (Community)
2.  Hello Mr. Pepito (Community)
3.  Hello Mr. Pepito (Community)
4.  Hello Mr. Pepito (Community)
5.  Hello Mr. Pepito (Community)
6.  Hello Mr. Pepito (Community)
7.  Hello Mr. Pepito (Community)
8.  Hello Mr. Pepito (Community)
9.  Hello Mr. Pepito (Community)
10. Hello Mr. Pepito (Community)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;different-flavors&quot;&gt;Different &quot;Flavors&quot;&lt;&#x2F;h4&gt;
&lt;p&gt;With a few lines more we can generate different versions of same application. In our example we are going to build &quot;Community&quot; and &quot;Enterprise&quot; flavors.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;build-gradle-flavors&quot;&gt;build.gradle (Flavors)&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;groovy&quot; class=&quot;language-groovy &quot;&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;apply plugin: &amp;#x27;cpp&amp;#x27;

model {
  flavors {
      community
      enterprise
  }

  components {
    hello(NativeLibrarySpec) {
      binaries.all {
        if (flavor == flavors.enterprise) {
          cppCompiler.define &amp;quot;ENTERPRISE&amp;quot;
        }
      }
    }
    main(NativeExecutableSpec) {
      binaries.all {
        lib library: &amp;quot;hello&amp;quot;
        }
    }
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We also have to prepare our application to use compilation parameters.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;msg-h&quot;&gt;Msg.h&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#ifdef ENTERPRISE
static const char * EDITION = &amp;quot;Enterprise&amp;quot;;

#else
static const char * EDITION = &amp;quot;Community&amp;quot;;

#endif
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this way it selects a string depending on used flavor.&lt;&#x2F;p&gt;
&lt;p&gt;If we execute &lt;code&gt;gradle clean task&lt;&#x2F;code&gt; in the root folder, we&#x27;ll get more available tasks. Before, we had &lt;code&gt;installMainExecutable&lt;&#x2F;code&gt; which has been replaced by &lt;code&gt;installCommunityMainExecutable&lt;&#x2F;code&gt; and &lt;code&gt;installEnterpriseMainExecutable&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we execute both tasks, we&#x27;ll get the application installed in both flavors:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$gradle installEnterpriseMainExecutable installCommunityMainExecutable

:compileEnterpriseHelloSharedLibraryHelloCpp
:linkEnterpriseHelloSharedLibrary
:enterpriseHelloSharedLibrary
:compileEnterpriseMainExecutableMainCpp
:linkEnterpriseMainExecutable
:enterpriseMainExecutable
:installEnterpriseMainExecutable
:compileCommunityHelloSharedLibraryHelloCpp
:linkCommunityHelloSharedLibrary
:communityHelloSharedLibrary
:compileCommunityMainExecutableMainCpp
:linkCommunityMainExecutable
:communityMainExecutable
:installCommunityMainExecutable

BUILD SUCCESSFUL
Total time: 9.414 secs
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can run the application in both flavors:&lt;&#x2F;p&gt;
&lt;h5 id=&quot;community&quot;&gt;Community&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ build&amp;#x2F;install&amp;#x2F;mainExecutable&amp;#x2F;community&amp;#x2F;main
1.      Hello Mr. Pepito        (Community)
2.      Hello Mr. Pepito        (Community)
3.      Hello Mr. Pepito        (Community)
4.      Hello Mr. Pepito        (Community)
5.      Hello Mr. Pepito        (Community)
6.      Hello Mr. Pepito        (Community)
7.      Hello Mr. Pepito        (Community)
8.      Hello Mr. Pepito        (Community)
9.      Hello Mr. Pepito        (Community)
10.     Hello Mr. Pepito        (Community)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h5 id=&quot;enterprise&quot;&gt;Enterprise&lt;&#x2F;h5&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ build&amp;#x2F;install&amp;#x2F;mainExecutable&amp;#x2F;enterprise&amp;#x2F;main
1.      Hello Mr. Pepito        (Enterprise)
2.      Hello Mr. Pepito        (Enterprise)
3.      Hello Mr. Pepito        (Enterprise)
4.      Hello Mr. Pepito        (Enterprise)
5.      Hello Mr. Pepito        (Enterprise)
6.      Hello Mr. Pepito        (Enterprise)
7.      Hello Mr. Pepito        (Enterprise)
8.      Hello Mr. Pepito        (Enterprise)
9.      Hello Mr. Pepito        (Enterprise)
10.     Hello Mr. Pepito        (Enterprise)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;release-or-debug&quot;&gt;Release or Debug&lt;&#x2F;h4&gt;
&lt;p&gt;By default Gradle compiles in Debug mode, but we can add the Release mode which enables several optimizations and remove debug flags&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#optimizations&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;optimizations&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;We can also specify&#x2F;modify which optimizations to apply.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;h4 id=&quot;build-gradle-release-debug&quot;&gt;build.gradle (Release&#x2F;Debug)&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;groovy&quot; class=&quot;language-groovy &quot;&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;apply plugin: &amp;#x27;cpp&amp;#x27;
model {
    buildTypes {
        debug
        release
    }
&amp;#x2F;&amp;#x2F; ... the rest of file below doesn&amp;#x27;t change
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we execute &lt;code&gt;gradle clean task&lt;&#x2F;code&gt; we will get more tasks, they have been split, for example &lt;code&gt;installCommunityMainExecutable&lt;&#x2F;code&gt; has been split in &lt;code&gt;installDebugCommunityMainExecutable&lt;&#x2F;code&gt; and &lt;code&gt;installReleaseCommunityMainExecutable&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;multi-platform&quot;&gt;Multi-platform&lt;&#x2F;h4&gt;
&lt;p&gt;Also we can use cross-compiling features provided by compilers and generate native components for other platforms. To do so we just have to add the supported platforms.&lt;&#x2F;p&gt;
&lt;p&gt;This only works if we have installed the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Toolchain&quot;&gt;Toolchain&lt;&#x2F;a&gt; for the target platform.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;build-gradle&quot;&gt;build.gradle&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;groovy&quot; class=&quot;language-groovy &quot;&gt;&lt;code class=&quot;language-groovy&quot; data-lang=&quot;groovy&quot;&gt;apply plugin: &amp;#x27;cpp&amp;#x27;

model {
  buildTypes {
    debug
    release
  }

  platforms {
    x86 {
      architecture &amp;quot;x86&amp;quot;
    }
    x64 {
      architecture &amp;quot;x86_64&amp;quot;
    }
    itanium {
      architecture &amp;quot;ia-64&amp;quot;
    }
  }

  flavors {
    community
    enterprise
  }

  components {
    hello(NativeLibrarySpec) {
      binaries.all {
        if (flavor == flavors.enterprise) {
          cppCompiler.define &amp;quot;ENTERPRISE&amp;quot;
        }
      }
    }
    main(NativeExecutableSpec) {
      binaries.all {
        lib library: &amp;quot;hello&amp;quot;
      }
    }
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When execute &lt;code&gt;gradle clean task&lt;&#x2F;code&gt; we get the different build options we have.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; In this example, we can build different versions of the application in different flavors for different platforms in Debug or Release mode.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;try-it-yourself&quot;&gt;Try it yourself&lt;&#x2F;h3&gt;
&lt;p&gt;You can find the project at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Requirements:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Java 6 or higher.&lt;&#x2F;li&gt;
&lt;li&gt;An installed compiler (e.g &lt;a href=&quot;https:&#x2F;&#x2F;gcc.gnu.org&#x2F;&quot;&gt;GCC&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You just have to follow next steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git clone git@github.com:carlosvin&#x2F;cpp_gradle.git&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cd cpp_gradle&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;.&#x2F;gradlew task&lt;&#x2F;code&gt; or &lt;code&gt;.&#x2F;gradlew.bat task&lt;&#x2F;code&gt; if you are in Windows. In this way you&#x27;ll see available tasks for this project. The first execution will take more time, because it downloads Gradle runtime.&lt;&#x2F;li&gt;
&lt;li&gt;If you are in a 64 bits platform, you can use this command to install the application: &lt;code&gt;.&#x2F;gradlew installX64ReleaseEnterpriseMainExecutable&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Run the application you just built: &lt;code&gt;build&#x2F;install&#x2F;mainExecutable&#x2F;x64ReleaseEnterprise&#x2F;main&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;&#x2F;h2&gt;
&lt;p&gt;With a small configuration file, we can achieve many different build combinations.&lt;&#x2F;p&gt;
&lt;p&gt;Gradle for C++ has a promising future, and I hope it will follow the successful path of Java and Android support.&lt;&#x2F;p&gt;
&lt;p&gt;It is well supported by continuous integration systems and offers many plugins and features.&lt;&#x2F;p&gt;
&lt;p&gt;However, Gradle for C++ is still under development, so we need to be cautious:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Do not use it in production environments.&lt;&#x2F;li&gt;
&lt;li&gt;Many things may change or be removed in future versions.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The full example is available at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&lt;&#x2F;a&gt;. I encourage you to try it yourself.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; If you find any issues in this example, please leave a comment, open an issue, or submit a fix at &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;cpp_gradle&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;For more information, see &lt;a href=&quot;https:&#x2F;&#x2F;docs.gradle.org&#x2F;current&#x2F;userguide&#x2F;native_software.html&quot;&gt;Getting Started with Gradle Native&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Embedded Java Databases - Performance Comparison</title>
        <published>2014-06-07T00:00:00+00:00</published>
        <updated>2014-06-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/java-embedded-db-performance-comparison/"/>
        <id>https://carlosvin.github.io/java-embedded-db-performance-comparison/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/java-embedded-db-performance-comparison/">&lt;h2 id=&quot;embedded-databases&quot;&gt;Embedded Databases&lt;&#x2F;h2&gt;
&lt;p&gt;These are databases that do not require a server, are embedded within the application itself, and are usually stored in local files. This, combined with the fact that they often have a mode where data is kept in memory, can result in very high performance.&lt;&#x2F;p&gt;
&lt;p&gt;However, this high degree of coupling to the application means they perform worse when shared between multiple applications due to access collisions.&lt;&#x2F;p&gt;
&lt;p&gt;Another advantage is that you don&#x27;t have to maintain and manage a database server.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m going to do a performance comparison between 3 transactional embedded databases (ACID). NoSQL databases are not included in this comparison as they are in a different performance league.&lt;&#x2F;p&gt;
&lt;p&gt;Contents&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sqlitedb&quot;&gt;SqliteDB&lt;&#x2F;h3&gt;
&lt;p&gt;This is a library written in &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;ANSI_C&quot;&gt;ANSI C&lt;&#x2F;a&gt;, less than 500KB, multi-platform, with no external dependencies, and stores all database content in a single file.&lt;&#x2F;p&gt;
&lt;p&gt;It gives the best performance in the test results below.&lt;&#x2F;p&gt;
&lt;p&gt;It can be used from C and C++, but also &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;Sqlite#Lenguajes_de_programaci.C3.B3n&quot;&gt;from other programming languages&lt;&#x2F;a&gt; (PHP, Python, Java, .NET ...).&lt;&#x2F;p&gt;
&lt;p&gt;In the case of Java, we can manage this database through JDBC. The library can be obtained from &lt;a href=&quot;https:&#x2F;&#x2F;bitbucket.org&#x2F;xerial&#x2F;sqlite-jdbc&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Here is an example of inserting a series of objects of the class &lt;a href=&quot;..&#x2F;java_embedded_databases&#x2F;blob&#x2F;master&#x2F;src&#x2F;main&#x2F;java&#x2F;domain&#x2F;Price.java&quot;&gt;Price.java&lt;&#x2F;a&gt;:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public class JdbcDb implements DB {
    enum Column {
        INSTRUMENT,
        MARKET,
        PRICE,
        DATE;
    }

    public static final String TABLE_NAME = &amp;quot;PRICES&amp;quot;;
    public static final String SQL_INSERT = &amp;quot;INSERT INTO &amp;quot; + TABLE_NAME
            + &amp;quot; (INSTRUMENT, MARKET, PRICE, DATE) VALUES (?,?,?,?)&amp;quot;;

    &amp;#x2F;&amp;#x2F; ...

    private void insert(Price p, PreparedStatement preparedStatement) throws SQLException {
        preparedStatement.setString(1, p.getInstrument());
        preparedStatement.setString(2, p.getMarket());
        preparedStatement.setDouble(3, p.getPrice());
        preparedStatement.setTimestamp(4, new Timestamp(p.getDate().getTime()));
        preparedStatement.addBatch();
    }

    @Override
    public void insert(Price... prices) throws SQLException {
        PreparedStatement preparedStatement = conn.prepareStatement(SQL_INSERT);
        for (Price p : prices) {
            insert(p, preparedStatement);
        }
        preparedStatement.executeBatch();
        preparedStatement.close();
        conn.commit();
    }
    &amp;#x2F;&amp;#x2F; ...
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;derbydb-or-javadb&quot;&gt;DerbyDB or JavaDB&lt;&#x2F;h3&gt;
&lt;p&gt;JavaDB is an Oracle distribution of the open-source DerbyDB database. It supports the &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;SQL&quot;&gt;ANSI&#x2F;ISO SQL&lt;&#x2F;a&gt; standard via JDBC and &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;Java_EE&quot;&gt;Java EE&lt;&#x2F;a&gt;. These libraries are included in the JDK.&lt;&#x2F;p&gt;
&lt;p&gt;It stores the database in multiple files, which can be useful for scaling storage.&lt;&#x2F;p&gt;
&lt;p&gt;It can only be used in Java, not from other languages.&lt;&#x2F;p&gt;
&lt;p&gt;As we will see later, it was the slowest in the test results.&lt;&#x2F;p&gt;
&lt;p&gt;The example implementation for inserting a series of objects of the class &lt;a href=&quot;..&#x2F;java_embedded_databases&#x2F;blob&#x2F;master&#x2F;src&#x2F;main&#x2F;java&#x2F;domain&#x2F;Price.java&quot;&gt;Price.java&lt;&#x2F;a&gt; is exactly the same as above for SqliteDB. This is one of the benefits of JDBC, which allows us to obtain a connection for a specific database, but from there we can almost always forget about the specific database as long as it supports our SQL queries.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;objectdb&quot;&gt;ObjectDB&lt;&#x2F;h3&gt;
&lt;p&gt;This is an &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;Base_de_datos_orientada_a_objetos&quot;&gt;object-oriented database&lt;&#x2F;a&gt; that allows access via &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;Java_Persistence_API&quot;&gt;JPA&lt;&#x2F;a&gt;, a Java standard that aims to retain the advantages of object orientation, which are often lost when dealing with persistence layers.&lt;&#x2F;p&gt;
&lt;p&gt;It is really easy to perform typical database actions, abstracting away from SQL. For example, here is how you would insert an array of Price objects with ObjectDB:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public void insert(Price... prices) throws SQLException {
    em.getTransaction().begin();
    for (Price p : prices) {
        em.persist(p);
    }
    em.getTransaction().commit();
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you add this ease of use to the fact that its performance in the test results was very good (close to SqliteDB), I can say that I have discovered an embedded database to consider for future Java projects. However, as with JavaDB, it is only useful if you are programming in Java.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-tests&quot;&gt;The Tests&lt;&#x2F;h2&gt;
&lt;p&gt;The tests simply consist of repeatedly performing a series of &lt;a href=&quot;https:&#x2F;&#x2F;es.wikipedia.org&#x2F;wiki&#x2F;CRUD&quot;&gt;CRUD&lt;&#x2F;a&gt; operations. For each database, the test performs a series of inserts, selects, updates, and deletions of objects of the Price class.&lt;&#x2F;p&gt;
&lt;p&gt;I used 100,000 instances of the &lt;a href=&quot;..&#x2F;java_embedded_databases&#x2F;blob&#x2F;master&#x2F;src&#x2F;main&#x2F;java&#x2F;domain&#x2F;Price.java&quot;&gt;Price.java&lt;&#x2F;a&gt; class, the same for each type of database.&lt;&#x2F;p&gt;
&lt;p&gt;For this, I created a &lt;a href=&quot;..&#x2F;java_embedded_databases&#x2F;blob&#x2F;master&#x2F;src&#x2F;main&#x2F;java&#x2F;db&#x2F;DB.java&quot;&gt;DB.java&lt;&#x2F;a&gt; interface that each implementation for each database shares.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public interface DB {
    public void insert(Price... prices) throws SQLException;
    public void createTable();
    public void deleteAll();
    public void update(Price... prices) throws SQLException;
    public Set&amp;lt;Price&amp;gt; selectAll();
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;jdbc-databases&quot;&gt;JDBC Databases&lt;&#x2F;h3&gt;
&lt;p&gt;Only the data needed to obtain the driver and the database connection changes, so all the logic is in the &lt;a href=&quot;..&#x2F;java_embedded_databases&#x2F;blob&#x2F;master&#x2F;src&#x2F;main&#x2F;java&#x2F;db&#x2F;JdbcDb.java&quot;&gt;JdbcDb.java&lt;&#x2F;a&gt; class, from which SqliteDB and DerbyDB inherit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;source-code&quot;&gt;Source Code&lt;&#x2F;h3&gt;
&lt;p&gt;You can download the source code from &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;java_embedded_databases&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It is a Gradle project, so to run the tests you just have to execute: &lt;code&gt;gradle test&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Gradle will automatically download the necessary libraries, compile, and run the tests.&lt;&#x2F;p&gt;
&lt;p&gt;You can also see the execution directly at &lt;a href=&quot;https:&#x2F;&#x2F;travis-ci.org&#x2F;carlosvin&#x2F;java_embedded_databases&quot;&gt;Travis CI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;travis-ci.org&#x2F;carlosvin&#x2F;java_embedded_databases.svg&quot; alt=&quot;Build Status&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;test-results&quot;&gt;Test Results&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;db.DbTest &amp;gt; testSqliteDB STANDARD_OUT
    Testing with 100000 elements
    100000 Prices SqliteDB, total time 3455 ms &amp;lt;1&amp;gt;
     Insert:  1508 ms
     Select:  605 ms
     Update:  1319 ms
     Delete:  23 ms
    ----------------------------------------------
db.DbTest &amp;gt; testObjectDB STANDARD_OUT
    Testing with 100000 elements
    100000 Prices ObjectDB, total time 6467 ms &amp;lt;2&amp;gt;
     Insert:  2579 ms
     Select:  1126 ms
     Update:  1698 ms
     Delete:  1064 ms
    ----------------------------------------------
db.DbTest &amp;gt; testDerbyDB STANDARD_OUT
    Testing with 100000 elements
    100000 Prices DerbyDB, total time 24808 ms &amp;lt;3&amp;gt;
     Insert:  11467 ms
     Select:  695 ms
     Update:  6983 ms
     Delete:  5663 ms
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&amp;lt;1&amp;gt; SqliteDB is the fastest.
&amp;lt;2&amp;gt; ObjectDB is twice as slow as SqliteDB.
&amp;lt;3&amp;gt; JavaDB or DerbyDB is the slowest, about 8 times slower than SqliteDB.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Java serialization ways: Performance Comparison</title>
        <published>2014-05-13T00:00:00+00:00</published>
        <updated>2014-05-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/serialization-java-serializable-externalizable/"/>
        <id>https://carlosvin.github.io/serialization-java-serializable-externalizable/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/serialization-java-serializable-externalizable/">&lt;p&gt;Recently I&#x27;ve had to serialize&#x2F;deserialize some data in &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; binary format. Lately I use &lt;a href=&quot;https:&#x2F;&#x2F;www.json.org&quot;&gt;JSON&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;XML&quot;&gt;XML&lt;&#x2F;a&gt; formats.&lt;&#x2F;p&gt;
&lt;p&gt;I remember that to serialize &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; objects they must implement the &lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Serializable.html&quot;&gt;Serializable&lt;&#x2F;a&gt; interface, but I had also read in Internet other way, implementing the &lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Externalizable.html&quot;&gt;Externalizable&lt;&#x2F;a&gt; interface, then, which interface must I implement? It depends on what you want such as everything in the life.&lt;&#x2F;p&gt;
&lt;p&gt;When to use &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#serializable&quot;&gt;Serializable&lt;&#x2F;a&gt; or &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#externalizable&quot;&gt;Externalizable&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;serializable&quot;&gt;Serializable&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;To serialize easily. You have to write less code.&lt;&#x2F;li&gt;
&lt;li&gt;This way has some restrictions: The object to serialize must implement the default constructor (0 args). It must be responsible to manage the parent class attributes.&lt;&#x2F;li&gt;
&lt;li&gt;The performance is not as important, we will see more about that in &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#performance-tests-serializable-vs-externalizable&quot;&gt;Performance tests (Serializable vs. Externalizable)&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;externalizable&quot;&gt;Externalizable&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;You must implement the serialization&#x2F;deserialization methods, so you have to write more code.&lt;&#x2F;li&gt;
&lt;li&gt;When you cannot use &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#serializable&quot;&gt;Serializable&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;When you want to improve the performance, as we&#x27;ll see in &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#performance-tests-serializable-vs-externalizable&quot;&gt;Performance tests (Serializable vs. Externalizable)&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;If you have to manage the serialization of parent class attributes, then I recommend you use &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#externalizable&quot;&gt;Externalizable&lt;&#x2F;a&gt;, because we&#x27;ll avoid a weird private methods overriding.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;private void writeObject(ObjectOutputStream oos)
private void readObject(ObjectInputStream ois)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;performance-tests-serializable-vs-externalizable&quot;&gt;Performance tests (Serializable vs. Externalizable)&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Serializable.html&quot;&gt;Serializable&lt;&#x2F;a&gt;: Java, through introspection, guesses the types of class attributes to know how to serialize&#x2F;deserialize them, but this &quot;magic&quot; is not free, it has a performance penalty.&lt;&#x2F;p&gt;
&lt;p&gt;When we use &lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Externalizable.html&quot;&gt;Externalizable&lt;&#x2F;a&gt; interface, we decide how to serialize&#x2F;deserialize, namely we have to write the code that does it. We&#x27;ve lost ease, but also we avoid that &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; does some tasks, so if we override the methods properly, we&#x27;ll get a performance improvement.&lt;&#x2F;p&gt;
&lt;p&gt;To know how big is the performance difference between both interfaces, I&#x27;ve written a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;serializations-performance-java&quot;&gt;tiny example in which we serialize an object with 2 collections with 100000 elements each one&lt;&#x2F;a&gt;. Here you can find the &lt;a href=&quot;http:&#x2F;&#x2F;carlosvin.github.io&#x2F;serializations-performance-java&#x2F;classes&#x2F;com.github.carlosvin.contacts.SerializationTest.html&quot;&gt;tests execution results&lt;&#x2F;a&gt;. There are 3 different implementations:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;implementing-serializable&quot;&gt;Implementing Serializable&lt;&#x2F;h3&gt;
&lt;p&gt;As we mentioned above, &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; has to guess certain things. During this process it sacrifices some of performance (slowest way), in exchange we get really simple source code, the class to serialize just has to implement the &lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Serializable.html&quot;&gt;Serializable&lt;&#x2F;a&gt; interface.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;public class Contacts implements Serializable {
  &amp;#x2F;&amp;#x2F; ...
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;serializing: 1133 millisecond&lt;&#x2F;li&gt;
&lt;li&gt;deserializing: 506 millisecond&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;implementing-externalizable-wrong-way&quot;&gt;Implementing Externalizable (wrong way)&lt;&#x2F;h3&gt;
&lt;p&gt;If the class implements &lt;a href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;7&#x2F;docs&#x2F;api&#x2F;java&#x2F;io&#x2F;Externalizable.html&quot;&gt;Externalizable&lt;&#x2F;a&gt;, we must tell to &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; how it has to serialize&#x2F;deserialize the class attributes. We just have to be careful, because if we did it bad, then we&#x27;ll get the worst of the both worlds: more complex implementation and bad performance, i.e: If we serialize&#x2F;deserialize complex class attributes (like collections), &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; will also have to guess many things about the attributes type.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
  setEmails((Set&amp;lt;String&amp;gt;) in.readObject());
  setPhones((Set&amp;lt;String&amp;gt;) in.readObject());
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {
  out.writeObject(emails);
  out.writeObject(phones);
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;serializing: 737 millisecond&lt;&#x2F;li&gt;
&lt;li&gt;deserializing: 367 millisecond&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;implementing-externalizable-right-way&quot;&gt;Implementing Externalizable (right way)&lt;&#x2F;h3&gt;
&lt;p&gt;If we serialize one by one the collection elements, then we&#x27;ll save more time, because &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; serializes simple types, this way avoids guessing things that we actually know.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;java&quot; class=&quot;language-java &quot;&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
  emails.clear();
  phones.clear();
  int nEmails = in.readInt();
  for (int i = 0; i &amp;lt; nEmails; i++) {
    emails.add(in.readUTF());
  }
  int nPhones = in.readInt();
  for (int i = 0; i &amp;lt; nPhones; i++) {
    phones.add(in.readUTF());
  }
}

@Override
public void writeExternal(ObjectOutput out) throws IOException {
  out.writeInt(emails.size());
  for (String e : emails) {
    out.writeUTF(e);
  }
  out.writeInt(phones.size());
  for (String p : phones) {
    out.writeUTF(p);
  }
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;serializing: 204 millisecond&lt;&#x2F;li&gt;
&lt;li&gt;deserializing: 92 millisecond&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We&#x27;ve gained performance at expense of write more code.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;results-analysis&quot;&gt;Results Analysis&lt;&#x2F;h3&gt;
&lt;p&gt;We don&#x27;t gain performance due to use an interface or the other one.&lt;&#x2F;p&gt;
&lt;p&gt;We gain performance because &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#externalizable&quot;&gt;Externalizable&lt;&#x2F;a&gt; interface forces us to implement ourselves the guessing code, so &lt;a href=&quot;https:&#x2F;&#x2F;www.java.com&quot;&gt;Java&lt;&#x2F;a&gt; doesn&#x27;t have to do that.&lt;&#x2F;p&gt;
&lt;p&gt;As we have seen at &lt;a href=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;serialization-java-serializable-externalizable&#x2F;#implementing-externalizable-wrong-way&quot;&gt;Implementing Externalizable (wrong way)&lt;&#x2F;a&gt;, si no tenemos cuidado, conseguiremos una mejora poco significativa a costa de complicar nuestro código fuente.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http:&#x2F;&#x2F;carlosvin.github.io&#x2F;serializations-performance-java&#x2F;classes&#x2F;com.github.carlosvin.contacts.SerializationTest.html&quot;&gt;Test results&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;carlosvin&#x2F;serializations-performance-java&#x2F;&quot;&gt;Code in Github&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Mutex C++</title>
        <published>2014-04-24T00:00:00+00:00</published>
        <updated>2014-04-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/cpp-mutex/"/>
        <id>https://carlosvin.github.io/cpp-mutex/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/cpp-mutex/">&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;C++11&quot;&gt;C++11&lt;&#x2F;a&gt; has added many improvements to help us developing multi-thread systems. I&#x27;m going to talk about &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Mutex&quot;&gt;Mutex&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In &lt;a href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;cxx_status.html&quot;&gt;previous C++11 compiler versions&lt;&#x2F;a&gt;, we can get a &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;POSIX_Threads&quot;&gt;pthread&lt;&#x2F;a&gt; mutex, but we must initialize it and destroy it in old C style, in the end you must do more things than just lock&#x2F;unlock.&lt;&#x2F;p&gt;
&lt;p&gt;With &lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;thread&#x2F;mutex&quot;&gt;C++11 Mutex Class&lt;&#x2F;a&gt;, we just lock&#x2F;unlock the object.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;mutex&amp;gt;

std::mutex mtx;

void do_something (int i) {
  mtx.lock();
  &amp;#x2F;&amp;#x2F; critical section
  mtx.unlock();
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Or you can just use Mutex with a &lt;a href=&quot;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;cpp&#x2F;thread&#x2F;lock_guard&quot;&gt;generic lock guard&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;&#x2F;strong&gt; If you still have to stick to previous C++11 compiler versions, maybe it is useful to you a wrapper class I created that helps you to work with pthread mutex, so you just have to lock&#x2F;unlock the Mutex object: &lt;a href=&quot;https:&#x2F;&#x2F;gist.github.com&#x2F;carlosvin&#x2F;11257689&quot;&gt;Gist code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Android Studio Portable Download</title>
        <published>2013-10-29T00:00:00+00:00</published>
        <updated>2013-10-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/android-studio-portable-download/"/>
        <id>https://carlosvin.github.io/android-studio-portable-download/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/android-studio-portable-download/">&lt;p&gt;If you want to use &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&quot;&gt;Android Studio&lt;&#x2F;a&gt; without installation, as a portable software, here you have the link to &lt;a href=&quot;https:&#x2F;&#x2F;developer.android.com&#x2F;studio&#x2F;preview&#x2F;&quot;&gt;last portable version of Android Studio&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Debugging library generated with libtool</title>
        <published>2013-02-01T15:30:00+00:00</published>
        <updated>2013-02-01T15:30:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/debug-libtool-lib/"/>
        <id>https://carlosvin.github.io/debug-libtool-lib/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/debug-libtool-lib/">&lt;p&gt;When debugging an executable that uses a library generated with &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;libtool&#x2F;libtool.html&quot;&gt;libtool&lt;&#x2F;a&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, you might encounter the following error:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;$ gdb .&amp;#x2F;tests-mylib
&amp;quot;tests-mylib&amp;quot;: not in executable format: File format not recognized
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;libmylib.so&lt;&#x2F;code&gt;: is a dynamic library generated with libtool.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;tests-mylib&lt;&#x2F;code&gt;: is an executable that uses the mylib library.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For those thinking I forgot to add the &lt;code&gt;-g&lt;&#x2F;code&gt; compilation option, this error occurs even when using &lt;code&gt;-g&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The error is due to the fact that we are trying to execute a script generated by libtool, which is a wrapper over the actual program to facilitate its execution&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;to-debug-our-test-program-tests-mylib&quot;&gt;To debug our test program &lt;code&gt;tests-mylib&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;libtool --mode=execute gdb tests-mylib
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Tool that belongs to the &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GNU_Build_System&quot;&gt;Autotools&lt;&#x2F;a&gt; used to create portable software libraries.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;More information in &lt;a href=&quot;https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;libtool&#x2F;manual&#x2F;libtool.html#Debugging-executables&quot;&gt;libtool documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>C++ Struct memory alignment</title>
        <published>2012-11-26T00:00:00+00:00</published>
        <updated>2012-11-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/cpp-pragma-pack/"/>
        <id>https://carlosvin.github.io/cpp-pragma-pack/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/cpp-pragma-pack/">&lt;p&gt;A C++ struct is an element that groups attributes with different types so we can manipulate them all together using same reference. It is like a class with public visibility by default for functions and attributes.&lt;&#x2F;p&gt;
&lt;p&gt;If we want to work in a lower level, closer to machine, it might be useful to understand how that data structure is stored in memory and how to control that mapping.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;struct-example&quot;&gt;Struct example&lt;&#x2F;h2&gt;
&lt;p&gt;It has two attributes: an integer (4 bytes) and a boolean (1 byte).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;struct SampleStruct {
    bool flag;
    unsigned int timeout;
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we get the instance size using &lt;code&gt;sizeof&lt;&#x2F;code&gt; we should get 5 bytes size and memory would be like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;cpp-pragma-pack&#x2F;.&#x2F;5b.png&quot; alt=&quot;5 bytes struct which uses 5 bytes in memory&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;But&lt;&#x2F;strong&gt; is not that simple, memory alignment depends on compiler and system. We will learn how to control compiler alignment policy, so we can avoid getting unexpected allocation memory sizes.&lt;&#x2F;p&gt;
&lt;p&gt;For example, in my local host, if I get the &lt;code&gt;sizeof&lt;&#x2F;code&gt; the previous structure without &lt;code&gt;pragma&lt;&#x2F;code&gt; declarations, &lt;strong&gt;I get a 8 bytes size&lt;&#x2F;strong&gt;. We are getting 8 Bytes instead of expected 5 Bytes because the compiler allocates more memory at the end of structure so it fits in 2n bytes blocks. Memory actually looks like:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;carlosvin.github.io&#x2F;cpp-pragma-pack&#x2F;.&#x2F;8b.png&quot; alt=&quot;5 bytes structure that actually spends 8 bytes in memory&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Example output:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;SampleStruct
flag: 1 Bytes
+
timeout: 4 Bytes
=
5 Bytes
sizeof struct:  8 Bytes
--
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;TIP: If we want to know the exact structure size we have to specify compiler how to align the memory, to do so we have &lt;code&gt;#pragma pack(n)&lt;&#x2F;code&gt; directive.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pragma-pack-directive-in-c-struct&quot;&gt;&lt;code&gt;#pragma pack&lt;&#x2F;code&gt; directive in C++ struct&lt;&#x2F;h2&gt;
&lt;p&gt;It is a preprocessor directive to indicate to compiler how to align data in memory.&lt;&#x2F;p&gt;
&lt;p&gt;Example with different memory alignment configurations:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#pragma pack (1)
struct SampleStructPack1 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

#pragma pack (2)
struct SampleStructPack2 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

#pragma pack (4)
struct SampleStructPack4 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

struct SampleStruct {
    bool flag;
    unsigned int timeout;
};
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Example output:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;SampleStructPack1
 flag: 1 Bytes
 +
 timeout: 4Bytes
 =
 5Bytes
 sizeof struct:  5 Bytes
 --

SampleStructPack2
 flag: 1 Bytes
 +
 timeout: 4Bytes
 =
 5Bytes
 sizeof struct:  6 Bytes

SampleStructPack4
 flag: 1 Bytes
 +
 timeout: 4Bytes
 =
 5Bytes
 sizeof struct:  8 Bytes

SampleStruct
 flag: 1 Bytes
 +
 timeout: 4Bytes
 =
 5Bytes
 sizeof struct:  8 Bytes
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;SampleStructPack1 &lt;code&gt;#pragma pack (1)&lt;&#x2F;code&gt;: It allocates 1 byte memory block, so our sample struct fits perfectly, in this case it is true that &lt;code&gt;4 + 1 = 5&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;SampleStructPack2 &lt;code&gt;#pragma pack (2)&lt;&#x2F;code&gt;: Minimum block size is 2 bytes. Integer attribute fits because it just needs 2 blocks of 2 Bytes. Boolean attribute needs just 1 Byte, but minimum block size is 2 Bytes, that&#x27;s why total allocated memory is 6 bytes, &lt;code&gt;4 + 2 = 6&lt;&#x2F;code&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;SampleStructPack4 &lt;code&gt;#pragma pack (4)&lt;&#x2F;code&gt;: It is like previous one, but in this case we are wasting more memory for boolean attribute, it needs 1 Byte, but we are allocating 4 Bytes.&lt;&#x2F;li&gt;
&lt;li&gt;SampleStruct (default compiler alignment): As you can see it behaves exactly like &lt;code&gt;#pragma pack (4)&lt;&#x2F;code&gt;, so we can deduce it is the default compiler alignment.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;&#x2F;strong&gt; Why don&#x27;t we always use smallest memory alignment (&lt;code&gt;#pragma pack (1)&lt;&#x2F;code&gt;) so we can save more memory?&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;WARNING:&lt;&#x2F;strong&gt; Because of performance loss.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;performance-test&quot;&gt;Performance test&lt;&#x2F;h2&gt;
&lt;p&gt;The test will allocate same number of elements in arrays for each structure type (1, 2, 4).&lt;&#x2F;p&gt;
&lt;p&gt;Example output:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;SampleStructPack1: 500000000000000000 bytes allocated in 94311 nanoseconds
SampleStructPack2: 600000000000000000 bytes allocated in 1777 nanoseconds
SampleStructPack4: 800000000000000000 bytes allocated in 1519 nanoseconds
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, the smallest memory alignment spends more time allocating and releasing memory.&lt;&#x2F;p&gt;
&lt;p&gt;Performance test source code:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp &quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;chrono&amp;gt;

#pragma pack (1)
struct SampleStructPack1 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

#pragma pack (2)
struct SampleStructPack2 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

#pragma pack (4)
struct SampleStructPack4 {
    bool flag;
    unsigned int timeout;
};
#pragma pack(0)

struct SampleStruct {
    bool flag;
    unsigned int timeout;
};

static const long MAX_ELEMENTS = 100000000000000000;
using namespace std;
using namespace std::chrono;

void allocate1() {
    SampleStructPack1 elements [MAX_ELEMENTS];
    cout &amp;lt;&amp;lt; &amp;quot;SampleStructPack1: &amp;quot; &amp;lt;&amp;lt; sizeof(elements) &amp;lt;&amp;lt; &amp;quot; bytes allocated&amp;quot;;
}

void allocate2() {
    SampleStructPack2 elements [MAX_ELEMENTS];
    cout &amp;lt;&amp;lt; &amp;quot;SampleStructPack2: &amp;quot; &amp;lt;&amp;lt; sizeof(elements) &amp;lt;&amp;lt; &amp;quot; bytes allocated&amp;quot;;
}

void allocate4() {
    SampleStructPack4 elements [MAX_ELEMENTS];
    cout &amp;lt;&amp;lt; &amp;quot;SampleStructPack4: &amp;quot; &amp;lt;&amp;lt; sizeof(elements) &amp;lt;&amp;lt; &amp;quot; bytes allocated&amp;quot;;
}

void chrono1() {
    auto begin = high_resolution_clock::now() ;
    allocate1();
    cout &amp;lt;&amp;lt; &amp;quot; in &amp;quot; &amp;lt;&amp;lt; duration_cast&amp;lt;nanoseconds&amp;gt;(high_resolution_clock::now() - begin).count() &amp;lt;&amp;lt; &amp;quot; nanoseconds&amp;quot; &amp;lt;&amp;lt; endl;
}

void chrono2() {
    auto begin = high_resolution_clock::now() ;
    allocate2();
    cout &amp;lt;&amp;lt; &amp;quot; in &amp;quot; &amp;lt;&amp;lt; duration_cast&amp;lt;nanoseconds&amp;gt;(high_resolution_clock::now() - begin).count() &amp;lt;&amp;lt; &amp;quot; nanoseconds&amp;quot; &amp;lt;&amp;lt; endl;
}

void chrono4() {
    auto begin = high_resolution_clock::now() ;
    allocate4();
    cout &amp;lt;&amp;lt; &amp;quot; in &amp;quot; &amp;lt;&amp;lt; duration_cast&amp;lt;nanoseconds&amp;gt;(high_resolution_clock::now() - begin).count() &amp;lt;&amp;lt; &amp;quot; nanoseconds&amp;quot; &amp;lt;&amp;lt; endl;
}

int main(int argc, char *argv[]) {
    chrono1();
    chrono2();
    chrono4();
    return 0;
}
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Proxy Configuration</title>
        <published>2012-11-15T12:00:00+00:00</published>
        <updated>2012-11-15T12:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/git-proxy-config/"/>
        <id>https://carlosvin.github.io/git-proxy-config/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/git-proxy-config/">&lt;p&gt;Working with Git through a corporate proxy can be challenging. Here&#x27;s a quick guide to configure Git proxy settings.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;configure-http-proxy&quot;&gt;Configure HTTP Proxy&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config --global http.proxy http:&amp;#x2F;&amp;#x2F;&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;ip_host&amp;gt;:&amp;lt;port&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;configure-https-proxy&quot;&gt;Configure HTTPS Proxy&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config --global https.proxy https:&amp;#x2F;&amp;#x2F;&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;ip_host&amp;gt;:&amp;lt;port&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;disable-proxy&quot;&gt;Disable Proxy&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config --global --unset http.proxy
git config --global --unset https.proxy
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;parameters&quot;&gt;Parameters&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;username&lt;&#x2F;code&gt;: Proxy username&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;password&lt;&#x2F;code&gt;: Proxy password&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;ip_host&lt;&#x2F;code&gt;: Proxy server address&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;port&lt;&#x2F;code&gt;: Proxy server port&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;verify-configuration&quot;&gt;Verify Configuration&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config --global --get http.proxy
git config --global --get https.proxy
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;more-secure-environment-variables&quot;&gt;More secure: Environment Variables&lt;&#x2F;h2&gt;
&lt;p&gt;Using environment variables is a more secure method, as entering credentials directly in commands can expose them in your shell history. Instead, set your proxy credentials using environment variables:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;export HTTP_PROXY=http:&amp;#x2F;&amp;#x2F;&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;ip_host&amp;gt;:&amp;lt;port&amp;gt;
export HTTPS_PROXY=https:&amp;#x2F;&amp;#x2F;&amp;lt;username&amp;gt;:&amp;lt;password&amp;gt;@&amp;lt;ip_host&amp;gt;:&amp;lt;port&amp;gt;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: Setting environment variables in the shell will also save them in the history, so this approach is more secure if you just set the environment variables in a file like &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; (if you are using &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bash_(Unix_shell)&quot;&gt;bash shell&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;For more details, see the &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-config&quot;&gt;official Git configuration documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Security Note:&lt;&#x2F;strong&gt; Storing credentials in environment variables or in files like &lt;code&gt;~&#x2F;.bash_profile&lt;&#x2F;code&gt; is not inherently secure, as these files are stored in plain text and can be read by anyone with access to your home directory. For better security, consider using &lt;a href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-credential&quot;&gt;Git credential helpers&lt;&#x2F;a&gt; or a dedicated credential manager. If you must store sensitive data in profile files, restrict access with &lt;code&gt;chmod 600 ~&#x2F;.bash_profile&lt;&#x2F;code&gt; to limit who can read the file.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Replace punctuation symbols in Python</title>
        <published>2012-10-23T00:00:00+00:00</published>
        <updated>2012-05-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/remove-replace-punctuation-py/"/>
        <id>https://carlosvin.github.io/remove-replace-punctuation-py/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/remove-replace-punctuation-py/">&lt;p&gt;Below is an explanation of how to replace punctuation symbols with whitespace in Python.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;import re, string

def remove_punctuation(text):
    return re.sub(&amp;#x27;[%s]&amp;#x27; % re.escape(string.punctuation), &amp;#x27; &amp;#x27;, text)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Calling the previous function:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; remove_punctuation(&amp;quot;El perro, de San Roque, no tiene rabo; ni nunca lo ha tenido.&amp;quot;)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;We will get this output:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&amp;#x27;El perro  de San Roque  no tiene rabo  ni nunca lo ha tenido &amp;#x27;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We could make the function a little bit more generic to replace punctuation symbols with any other string.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;import re, string

def replace_punctuation(text, replace):
    return re.sub(&amp;#x27;[%s]&amp;#x27; % re.escape(string.punctuation), replace, text)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Calling the function to replace punctuation symbols by &quot;[stop]&quot;:&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; replace_punctuation(
    &amp;quot;El perro, de San Roque, no tiene rabo; ni nunca lo ha tenido.&amp;quot;,
    &amp;#x27;[stop]&amp;#x27;)

# output
&amp;#x27;El perro[stop] de San Roque[stop] no tiene rabo[stop] ni nunca lo ha tenido[stop]&amp;#x27;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Text Normalization in Python</title>
        <published>2012-10-02T18:00:00+00:00</published>
        <updated>2012-10-02T18:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/normalize-text-py/"/>
        <id>https://carlosvin.github.io/normalize-text-py/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/normalize-text-py/">&lt;p&gt;In many languages, such as Spanish, there are characters that do not have &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII&quot;&gt;ASCII&lt;&#x2F;a&gt; representation, such as &lt;strong&gt;á&lt;&#x2F;strong&gt;, which does have representation in &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unicode&quot;&gt;Unicode&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To avoid problems or for simplification, an equivalence has been established between &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unicode&quot;&gt;Unicode&lt;&#x2F;a&gt; and &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII&quot;&gt;ASCII&lt;&#x2F;a&gt; characters. Below I&#x27;ll show you a piece of &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&quot;&gt;Python&lt;&#x2F;a&gt; code that performs this conversion.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;# -*- coding: utf-8 -*-
from unicodedata import normalize

def normalize_text(text):
    return normalize(&amp;#x27;NFKD&amp;#x27;, text)  # (1)
        .encode(&amp;#x27;ASCII&amp;#x27;, &amp;#x27;ignore&amp;#x27;)  # (2)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;We specify the normal form that we apply in the normalization. In this case &lt;code&gt;NFKD&lt;&#x2F;code&gt;. More information about &lt;a href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Unicode_equivalence#Normal_forms&quot;&gt;normal form types&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;We convert the normalization result to ASCII. In case a character is erroneous, it will simply be ignored.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;running-the-function&quot;&gt;Running the function&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&amp;gt;&amp;gt;&amp;gt; normalize_text(&amp;#x27;aáaá eéeé iíií oóoó ñnñn AÀAÀ&amp;#x27;)
b&amp;#x27;aaaa eeee iiii oooo nnnn AAAA&amp;#x27;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Remove HTML Tags</title>
        <published>2012-10-02T11:30:00+00:00</published>
        <updated>2012-10-02T11:30:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/delete-html-tags-py-django/"/>
        <id>https://carlosvin.github.io/delete-html-tags-py-django/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/delete-html-tags-py-django/">&lt;p&gt;Below we&#x27;ll see how to remove HTML tags from a character string.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;with-python&quot;&gt;With Python&lt;&#x2F;h2&gt;
&lt;p&gt;Function responsible for removing HTML tags:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;main-py&quot;&gt;main.py&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;import re

def strip_tags(value):
    return re.sub(r&amp;#x27;&amp;lt;[^&amp;gt;]*?&amp;gt;&amp;#x27;, &amp;#x27;&amp;#x27;, value)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s test an HTML fragment with the &lt;code&gt;strip_tags&lt;&#x2F;code&gt; function:&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-usage&quot;&gt;Example usage&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;import re

def strip_tags(value):
    return re.sub(r&amp;#x27;&amp;lt;[^&amp;gt;]*?&amp;gt;&amp;#x27;, &amp;#x27;&amp;#x27;, value)

html_text = &amp;quot;&amp;quot;&amp;quot;
    &amp;lt;!DOCTYPE HTML&amp;gt;
    &amp;lt;html&amp;gt;
        &amp;lt;head&amp;gt;
            &amp;lt;title&amp;gt;Title&amp;lt;&amp;#x2F;title&amp;gt;
        &amp;lt;&amp;#x2F;head&amp;gt;
        &amp;lt;body&amp;gt;
            &amp;lt;p&amp;gt;Paragraph&amp;lt;&amp;#x2F;p&amp;gt;
        &amp;lt;&amp;#x2F;body&amp;gt;
    &amp;lt;&amp;#x2F;html&amp;gt;&amp;quot;&amp;quot;&amp;quot;

print(strip_tags(html_text))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we run the script we get the following result:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Title

Paragraph
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If it was easy with &lt;a href=&quot;https:&#x2F;&#x2F;www.python.org&quot;&gt;Python&lt;&#x2F;a&gt;, let&#x27;s see how it works with &lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&quot;&gt;Django&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;django&quot;&gt;Django&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;www.djangoproject.com&quot;&gt;Django&lt;&#x2F;a&gt; offers a function for this: &lt;a href=&quot;https:&#x2F;&#x2F;docs.djangoproject.com&#x2F;en&#x2F;3.0&#x2F;ref&#x2F;utils&#x2F;#django.utils.html.strip_tags&quot;&gt;&lt;code&gt;strip_tags&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First, you just need to install the library: &lt;code&gt;pip install django&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;using-django-s-strip-tags&quot;&gt;Using Django&#x27;s strip_tags&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python &quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;from django.utils.html import strip_tags

html_text = &amp;quot;&amp;quot;&amp;quot;
    &amp;lt;!DOCTYPE HTML&amp;gt;
    &amp;lt;html&amp;gt;
        &amp;lt;head&amp;gt;
            &amp;lt;title&amp;gt;Title&amp;lt;&amp;#x2F;title&amp;gt;
        &amp;lt;&amp;#x2F;head&amp;gt;
        &amp;lt;body&amp;gt;
            &amp;lt;p&amp;gt;Paragraph&amp;lt;&amp;#x2F;p&amp;gt;
        &amp;lt;&amp;#x2F;body&amp;gt;
    &amp;lt;&amp;#x2F;html&amp;gt;&amp;quot;&amp;quot;&amp;quot;

print(strip_tags(html_text))
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Remove orphaned packages (Linux)</title>
        <published>2012-10-02T00:00:00+00:00</published>
        <updated>2012-10-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Carlos Martin Sanchez
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://carlosvin.github.io/linux-remove-orphaned-files/"/>
        <id>https://carlosvin.github.io/linux-remove-orphaned-files/</id>
        
        <content type="html" xml:base="https://carlosvin.github.io/linux-remove-orphaned-files/">&lt;p&gt;When we install a package in most Linux distributions, the package system installs other packages needed by the package that we are installing. If we uninstall the package, its dependencies might not be uninstalled; these unused dependencies are called orphaned packages.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s see how to remove orphaned packages.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;archlinux&quot;&gt;Archlinux&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;pacman -Rsn $(pacman -Qdtq)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;How does the command work?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pacman -Qdt&lt;&#x2F;code&gt; lists all orphaned packages&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pacman -Rsn&lt;&#x2F;code&gt; uninstalls the listed packages&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;debian&quot;&gt;Debian&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;apt-get remove --purge $(deborphan)
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</content>
        
    </entry>
</feed>
