<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>The Hov</title><link href="https://www.tighov.link/" rel="alternate"></link><link href="https://www.tighov.link/feeds/all.atom.xml" rel="self"></link><id>https://www.tighov.link/</id><updated>2026-05-28T09:00:00+04:00</updated><entry><title>Why Kubernetes is a strategic infrastructure platform for modern companies</title><link href="https://www.tighov.link/why-kubernetes-is-a-strategic-infrastructure-platform-for-modern-companies.html" rel="alternate"></link><published>2026-05-28T09:00:00+04:00</published><updated>2026-05-28T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-28:/why-kubernetes-is-a-strategic-infrastructure-platform-for-modern-companies.html</id><summary type="html">&lt;p&gt;Kubernetes gives companies a platform to standardize infrastructure, accelerate delivery, and reduce risk.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes is more than a container orchestration engine. For modern companies, it is a strategic infrastructure platform that aligns development, operations, and business goals.&lt;/p&gt;
&lt;h3&gt;Standardizing infrastructure across teams&lt;/h3&gt;
&lt;p&gt;Companies with multiple product teams often suffer from inconsistent deployment patterns, fragile environments, and slow onboarding. Kubernetes provides a shared platform abstraction that standardizes how applications run, how they consume resources, and how teams deploy changes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistent scheduling and deployment semantics&lt;/li&gt;
&lt;li&gt;Uniform networking and service discovery&lt;/li&gt;
&lt;li&gt;Shared observability and policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This consistency reduces friction between teams and lowers the operational cost of supporting multiple applications.&lt;/p&gt;
&lt;h3&gt;Enabling platform-led growth&lt;/h3&gt;
&lt;p&gt;A Kubernetes platform lets infrastructure teams offer opinionated, reusable building blocks rather than one-off environments. That means business teams can move faster while platform teams retain control over security, compliance, and cost.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Platform APIs for deployments, ingress, storage&lt;/li&gt;
&lt;li&gt;Reusable environment blueprints for dev, staging, production&lt;/li&gt;
&lt;li&gt;Guardrails that prevent risky changes without blocking innovation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reducing vendor and infrastructure lock-in&lt;/h3&gt;
&lt;p&gt;Because Kubernetes is supported by all major cloud providers as well as on-premises distributions, companies can design infrastructure with flexibility in mind. Applications packaged for Kubernetes can move between cloud, hybrid, and edge environments with far less rewiring than traditional VM-based stacks.&lt;/p&gt;
&lt;h3&gt;Why this matters for business&lt;/h3&gt;
&lt;p&gt;Kubernetes helps companies shift infrastructure from a tactical expense to a strategic capability. It enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;faster time-to-market for new services&lt;/li&gt;
&lt;li&gt;more predictable operations&lt;/li&gt;
&lt;li&gt;better alignment between IT and business objectives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In short, Kubernetes supports infrastructure as a platform, not just infrastructure as plumbing. That becomes a powerful differentiator for companies that want to run reliable, scalable digital experiences.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="cloud"></category><category term="devops"></category></entry><entry><title>How Kubernetes enables resilient, scalable business workloads</title><link href="https://www.tighov.link/how-kubernetes-enables-resilient-scalable-business-workloads.html" rel="alternate"></link><published>2026-05-27T09:00:00+04:00</published><updated>2026-05-27T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-27:/how-kubernetes-enables-resilient-scalable-business-workloads.html</id><summary type="html">&lt;p&gt;Kubernetes helps businesses build resilient, scalable workloads by automating recovery, scaling, and resource management.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes is designed to keep workloads running even when infrastructure fails. For businesses, that resiliency translates into higher availability and lower risk for revenue-critical services.&lt;/p&gt;
&lt;h3&gt;Built-in recovery and self-healing&lt;/h3&gt;
&lt;p&gt;Kubernetes constantly monitors application health and takes action when something breaks. That means clusters can recover from container failures, node failures, or transient network issues automatically.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pod restart policies restore unhealthy containers&lt;/li&gt;
&lt;li&gt;ReplicaSets maintain the desired number of replicas&lt;/li&gt;
&lt;li&gt;Node eviction and rescheduling keep workloads alive despite failures&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This automated recovery is a major advantage for business workloads that cannot afford long outages.&lt;/p&gt;
&lt;h3&gt;Autoscaling for demand-driven load&lt;/h3&gt;
&lt;p&gt;Modern business traffic is rarely constant. Kubernetes supports multiple autoscaling mechanisms that adjust capacity based on actual load.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Horizontal Pod Autoscaler scales application replicas&lt;/li&gt;
&lt;li&gt;Vertical Pod Autoscaler adjusts container resource requests&lt;/li&gt;
&lt;li&gt;Cluster Autoscaler scales the underlying node pool&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means companies can handle spikes without massive overprovisioning, while still preserving performance for normal traffic.&lt;/p&gt;
&lt;h3&gt;Isolation and predictable performance&lt;/h3&gt;
&lt;p&gt;Kubernetes lets teams define resource boundaries so that one service cannot starve another. Quality of service classes, resource requests, and limits help ensure predictable performance in noisy multi-tenant environments.&lt;/p&gt;
&lt;h3&gt;Business benefit&lt;/h3&gt;
&lt;p&gt;Resilience and scalability are not just technical goals. They are business enablers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;improved customer trust through reliable service&lt;/li&gt;
&lt;li&gt;reduced downtime costs&lt;/li&gt;
&lt;li&gt;the ability to launch new features at scale&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For infrastructure leaders, Kubernetes is a platform that turns resilience from a manual operational effort into a repeatable capability.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="resilience"></category><category term="scalability"></category></entry><entry><title>Kubernetes cost efficiency: driving better resource utilization</title><link href="https://www.tighov.link/kubernetes-cost-efficiency-driving-better-resource-utilization.html" rel="alternate"></link><published>2026-05-26T09:00:00+04:00</published><updated>2026-05-26T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-26:/kubernetes-cost-efficiency-driving-better-resource-utilization.html</id><summary type="html">&lt;p&gt;Kubernetes helps companies improve cost efficiency by optimizing compute usage and reducing waste across infrastructure.&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the strongest business cases for Kubernetes is cost efficiency. By using compute more effectively and enabling dynamic scaling, Kubernetes helps companies reduce infrastructure waste.&lt;/p&gt;
&lt;h3&gt;Stop paying for idle resources&lt;/h3&gt;
&lt;p&gt;Traditional VM-centric infrastructure often requires teams to provision capacity for peak traffic. Kubernetes changes that model by enabling workloads to scale up and down automatically.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;autoscaling based on CPU, memory, or custom metrics&lt;/li&gt;
&lt;li&gt;bin packing of workloads onto fewer nodes&lt;/li&gt;
&lt;li&gt;support for bursty, event-driven workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When infrastructure adjusts to demand, companies avoid paying for unused capacity.&lt;/p&gt;
&lt;h3&gt;Share cluster infrastructure safely&lt;/h3&gt;
&lt;p&gt;Kubernetes clusters allow multiple teams to share the same underlying compute while maintaining isolation through namespaces, network policies, and resource quotas.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fewer clusters to manage&lt;/li&gt;
&lt;li&gt;improved utilization from workload consolidation&lt;/li&gt;
&lt;li&gt;central controls for cost governance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This shared model is a powerful lever for companies that want to manage more applications with the same staff and budget.&lt;/p&gt;
&lt;h3&gt;Optimize cloud and hybrid spending&lt;/h3&gt;
&lt;p&gt;Kubernetes workloads can be moved between on-prem and cloud infrastructure, or split across both, depending on cost and compliance needs.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use spot/preemptible instances for non-critical workloads&lt;/li&gt;
&lt;li&gt;reserve stable capacity for core services&lt;/li&gt;
&lt;li&gt;shift batch workloads to lower-cost environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why businesses care&lt;/h3&gt;
&lt;p&gt;At the platform level, Kubernetes provides visibility into where money is spent and how to reduce it. That helps align engineering decisions with financial goals and makes infrastructure a contributor to profitability.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="cost"></category><category term="optimization"></category></entry><entry><title>Accelerating delivery with Kubernetes and GitOps</title><link href="https://www.tighov.link/accelerating-delivery-with-kubernetes-and-gitops.html" rel="alternate"></link><published>2026-05-25T09:00:00+04:00</published><updated>2026-05-25T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-25:/accelerating-delivery-with-kubernetes-and-gitops.html</id><summary type="html">&lt;p&gt;Kubernetes combined with GitOps creates a delivery model that speeds releases, improves reliability, and simplifies rollbacks.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes and GitOps form a powerful duo for engineering organizations. They turn infrastructure and application deployment into version-controlled, observable processes.&lt;/p&gt;
&lt;h3&gt;Infrastructure as code for platforms&lt;/h3&gt;
&lt;p&gt;GitOps treats the desired state of a Kubernetes cluster as code stored in Git. That means changes to deployments, services, config maps, and policies are reviewed and audited like any software change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;declarative cluster state&lt;/li&gt;
&lt;li&gt;automated reconciliation by controllers&lt;/li&gt;
&lt;li&gt;version history for drift detection&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This model reduces manual intervention and improves confidence in every release.&lt;/p&gt;
&lt;h3&gt;Faster, safer rollouts&lt;/h3&gt;
&lt;p&gt;GitOps pipelines can deploy new versions automatically once changes are merged. If something goes wrong, the same pipeline can roll back to a known good state.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;automated canary or blue-green strategies&lt;/li&gt;
&lt;li&gt;clear audit trail of who changed what and when&lt;/li&gt;
&lt;li&gt;consistent deployment behavior across environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That makes teams more comfortable deploying often, which is a key driver of business agility.&lt;/p&gt;
&lt;h3&gt;Aligning development and operations&lt;/h3&gt;
&lt;p&gt;Kubernetes makes it easier for developers to own application behavior, while platform teams define the runtime environment. GitOps bridges this gap by using a single source of truth.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;developers request changes through Git&lt;/li&gt;
&lt;li&gt;platform operators enforce cluster policies centrally&lt;/li&gt;
&lt;li&gt;both sides see the same manifest and history&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business impact&lt;/h3&gt;
&lt;p&gt;For companies, GitOps on Kubernetes means fewer deployment errors, faster time-to-market, and better predictability. It turns infrastructure delivery from a bottleneck into a competitive advantage.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="gitops"></category><category term="delivery"></category></entry><entry><title>Kubernetes for hybrid and multi-cloud infrastructure</title><link href="https://www.tighov.link/kubernetes-for-hybrid-and-multi-cloud-infrastructure.html" rel="alternate"></link><published>2026-05-24T09:00:00+04:00</published><updated>2026-05-24T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-24:/kubernetes-for-hybrid-and-multi-cloud-infrastructure.html</id><summary type="html">&lt;p&gt;Kubernetes gives companies a consistent platform for hybrid and multi-cloud infrastructure, reducing operational complexity and risk.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Hybrid and multi-cloud are now strategic realities for many companies. Kubernetes provides the portability and consistency needed to manage workloads across multiple environments.&lt;/p&gt;
&lt;h3&gt;A shared control plane for different clouds&lt;/h3&gt;
&lt;p&gt;While clouds differ in services and APIs, Kubernetes provides a common runtime abstraction for containers across providers. That enables teams to deploy the same application manifests to different targets with minimal change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;same deployment and service model across AWS, GCP, Azure, and on-prem&lt;/li&gt;
&lt;li&gt;reuse tooling for CI/CD, observability, and security&lt;/li&gt;
&lt;li&gt;simplified developer experience&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This common foundation reduces the cost of operating in multiple clouds.&lt;/p&gt;
&lt;h3&gt;Enabling geographic and compliance flexibility&lt;/h3&gt;
&lt;p&gt;Some workloads need to run close to customers, while others must stay in specific regions for compliance. Kubernetes clusters can be placed where they are needed, while the application definition remains consistent.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;regional clusters for latency-sensitive workloads&lt;/li&gt;
&lt;li&gt;data residency and sovereignty controls&lt;/li&gt;
&lt;li&gt;disaster recovery across providers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Reducing cloud lock-in&lt;/h3&gt;
&lt;p&gt;Kubernetes lets companies avoid building application stacks that are too tightly bound to a single cloud provider’s proprietary APIs. The more business-critical capabilities are built around portable Kubernetes primitives, the easier it is to move or expand later.&lt;/p&gt;
&lt;h3&gt;Business value&lt;/h3&gt;
&lt;p&gt;A hybrid and multi-cloud Kubernetes strategy can improve resilience, meet compliance demands, and preserve strategic flexibility. For companies, that means infrastructure decisions become assets rather than constraints.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="hybrid-cloud"></category><category term="multi-cloud"></category></entry><entry><title>Operational visibility and reliability with Kubernetes</title><link href="https://www.tighov.link/operational-visibility-and-reliability-with-kubernetes.html" rel="alternate"></link><published>2026-05-23T09:00:00+04:00</published><updated>2026-05-23T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-23:/operational-visibility-and-reliability-with-kubernetes.html</id><summary type="html">&lt;p&gt;Kubernetes gives teams the observability and reliability controls needed to run business-critical services with confidence.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes is a platform that not only runs workloads but also exposes the operational signals teams need to keep those workloads healthy.&lt;/p&gt;
&lt;h3&gt;Observable platform primitives&lt;/h3&gt;
&lt;p&gt;Kubernetes provides rich data about containers, pods, nodes, and services. This observability makes it easier to answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;which services are failing?&lt;/li&gt;
&lt;li&gt;where are resource bottlenecks?&lt;/li&gt;
&lt;li&gt;how is traffic routed between workloads?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That data is invaluable for platform teams and business stakeholders alike.&lt;/p&gt;
&lt;h3&gt;Reliability through declarative state&lt;/h3&gt;
&lt;p&gt;Because Kubernetes operates on a desired-state model, it can continuously reconcile actual state with the target state defined by operators.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;failed pods are replaced automatically&lt;/li&gt;
&lt;li&gt;misconfigurations are detected when manifests no longer match&lt;/li&gt;
&lt;li&gt;deployment progress can be observed and halted if it violates policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This constant reconciliation preserves reliability without requiring manual intervention.&lt;/p&gt;
&lt;h3&gt;Support for SRE practices&lt;/h3&gt;
&lt;p&gt;Kubernetes aligns well with site reliability engineering (SRE) practices by enabling service-level objectives, error budgets, and incident response workflows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;readiness and liveness probes define service health&lt;/li&gt;
&lt;li&gt;circuit-breaker and retry patterns are easier to enforce&lt;/li&gt;
&lt;li&gt;alerts can be based on infrastructure and application metrics&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Why it matters for business&lt;/h3&gt;
&lt;p&gt;When a business runs critical workloads, observability and reliability are non-negotiable. Kubernetes helps teams detect issues earlier, recover faster, and keep service quality aligned with customer expectations.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="observability"></category><category term="reliability"></category></entry><entry><title>How Kubernetes supports developer productivity and platform teams</title><link href="https://www.tighov.link/how-kubernetes-supports-developer-productivity-and-platform-teams.html" rel="alternate"></link><published>2026-05-22T09:00:00+04:00</published><updated>2026-05-22T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-22:/how-kubernetes-supports-developer-productivity-and-platform-teams.html</id><summary type="html">&lt;p&gt;Kubernetes supports both developer productivity and platform teams by exposing a consistent runtime and reusable platform services.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes is often framed as an operations tool, but it also has a strong productivity story for developers and platform teams.&lt;/p&gt;
&lt;h3&gt;A consistent developer experience&lt;/h3&gt;
&lt;p&gt;When all teams deploy to the same platform, developers can learn one set of deployment patterns and focus on application logic rather than environment specifics.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;standard manifest formats&lt;/li&gt;
&lt;li&gt;shared CI/CD pipelines&lt;/li&gt;
&lt;li&gt;consistent service discovery and configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This consistency reduces onboarding time and helps developers move faster.&lt;/p&gt;
&lt;h3&gt;Platform teams enable rather than block&lt;/h3&gt;
&lt;p&gt;Platform engineering teams build opinionated abstractions on top of Kubernetes: reusable deployment templates, service catalogs, and policy guards.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;developers consume ready-made runtime services&lt;/li&gt;
&lt;li&gt;platform teams enforce security and compliance centrally&lt;/li&gt;
&lt;li&gt;the friction between build and run is reduced&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That makes infrastructure governance scalable across many teams.&lt;/p&gt;
&lt;h3&gt;Faster iteration with safe defaults&lt;/h3&gt;
&lt;p&gt;Kubernetes lets teams define safe defaults for networking, storage, and compute. Developers then inherit those defaults without needing deep platform expertise.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;common ingress and TLS setup&lt;/li&gt;
&lt;li&gt;standardized storage classes&lt;/li&gt;
&lt;li&gt;default resource limits and quotas&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business impact&lt;/h3&gt;
&lt;p&gt;For companies, this means faster product development cycles, fewer environment-related bugs, and platform teams that can support growth without burning out.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="productivity"></category><category term="platform-engineering"></category></entry><entry><title>Securing business-critical workloads on Kubernetes</title><link href="https://www.tighov.link/securing-business-critical-workloads-on-kubernetes.html" rel="alternate"></link><published>2026-05-21T09:00:00+04:00</published><updated>2026-05-21T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-21:/securing-business-critical-workloads-on-kubernetes.html</id><summary type="html">&lt;p&gt;Kubernetes helps companies secure business-critical workloads through policies, isolation, and supply chain controls.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Running business-critical applications on Kubernetes introduces new security opportunities and responsibilities. When done right, Kubernetes can strengthen the overall security posture.&lt;/p&gt;
&lt;h3&gt;Isolation and access control&lt;/h3&gt;
&lt;p&gt;Kubernetes supports namespace isolation, role-based access control (RBAC), and network policies that help separate workloads and limit blast radius.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;isolate teams and applications using namespaces&lt;/li&gt;
&lt;li&gt;enforce least privilege with RBAC&lt;/li&gt;
&lt;li&gt;restrict traffic using Kubernetes-native network policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This creates a more predictable security boundary than ad hoc infrastructure setups.&lt;/p&gt;
&lt;h3&gt;Policy-driven compliance&lt;/h3&gt;
&lt;p&gt;Tools like Open Policy Agent (OPA) and Gatekeeper allow companies to enforce policies across Kubernetes manifests before deployment.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deny insecure container settings&lt;/li&gt;
&lt;li&gt;require approved ingress and egress rules&lt;/li&gt;
&lt;li&gt;ensure secrets and config maps follow standards&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means compliance checks become part of the deployment workflow instead of manual audits.&lt;/p&gt;
&lt;h3&gt;Securing the supply chain&lt;/h3&gt;
&lt;p&gt;Kubernetes workloads benefit from container image scanning, signed manifests, and runtime admission controls.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;scan images for vulnerabilities before deployment&lt;/li&gt;
&lt;li&gt;verify image provenance with signing&lt;/li&gt;
&lt;li&gt;block unapproved images via admission controllers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business benefit&lt;/h3&gt;
&lt;p&gt;For companies, these controls reduce risk to revenue and reputation. Kubernetes helps make security measurable and repeatable, especially for infrastructure that supports sensitive or regulated workloads.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="security"></category><category term="compliance"></category></entry><entry><title>Running batch, stateful, and AI workloads on Kubernetes</title><link href="https://www.tighov.link/running-batch-stateful-and-ai-workloads-on-kubernetes.html" rel="alternate"></link><published>2026-05-20T09:00:00+04:00</published><updated>2026-05-20T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-20:/running-batch-stateful-and-ai-workloads-on-kubernetes.html</id><summary type="html">&lt;p&gt;Kubernetes is a versatile platform for batch jobs, stateful services, and AI workloads that businesses need to run efficiently.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Kubernetes is often associated with stateless web apps, but it is also a strong platform for batch, stateful, and AI workloads.&lt;/p&gt;
&lt;h3&gt;Batch workloads with elastic capacity&lt;/h3&gt;
&lt;p&gt;Kubernetes handles short-lived jobs and batch processing by scheduling containers only when they are needed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run jobs with Kubernetes Jobs and CronJobs&lt;/li&gt;
&lt;li&gt;scale worker capacity based on queue depth&lt;/li&gt;
&lt;li&gt;use spot instances for cost-sensitive workloads&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This flexibility makes batch processing more responsive and less expensive.&lt;/p&gt;
&lt;h3&gt;Stateful services in containers&lt;/h3&gt;
&lt;p&gt;Kubernetes has matured support for stateful workloads through StatefulSets, persistent volumes, and storage classes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stable network identities for stateful pods&lt;/li&gt;
&lt;li&gt;reclaimable persistent storage&lt;/li&gt;
&lt;li&gt;predictable scaling for databases and caches&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That means companies can run databases, message queues, and other stateful components alongside stateless services.&lt;/p&gt;
&lt;h3&gt;AI and data workloads&lt;/h3&gt;
&lt;p&gt;AI workloads benefit from Kubernetes’ ability to manage specialized resources like GPUs and large-scale distributed training.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;schedule GPU-backed pods with device plugins&lt;/li&gt;
&lt;li&gt;use custom resource definitions for AI frameworks&lt;/li&gt;
&lt;li&gt;integrate with data pipelines and feature stores&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business advantage&lt;/h3&gt;
&lt;p&gt;For organizations building data products, Kubernetes reduces the need for separate execution platforms. It can support a broad spectrum of workloads on a single infrastructure stack.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="workload-management"></category><category term="ai"></category></entry><entry><title>Choosing Kubernetes for long-term infrastructure agility</title><link href="https://www.tighov.link/choosing-kubernetes-for-long-term-infrastructure-agility.html" rel="alternate"></link><published>2026-05-19T09:00:00+04:00</published><updated>2026-05-19T09:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2026-05-19:/choosing-kubernetes-for-long-term-infrastructure-agility.html</id><summary type="html">&lt;p&gt;Kubernetes supports long-term infrastructure agility by making applications portable, manageable, and easier to evolve.&lt;/p&gt;</summary><content type="html">&lt;p&gt;When companies choose infrastructure, they should think beyond the next project. Kubernetes is a strong choice for long-term agility because it enables portability, standardization, and evolving architectures.&lt;/p&gt;
&lt;h3&gt;Portability across environments&lt;/h3&gt;
&lt;p&gt;Kubernetes decouples application packaging from the underlying compute infrastructure. That means teams can move workloads between cloud providers, on-premises clusters, and edge environments with less friction.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use the same container images everywhere&lt;/li&gt;
&lt;li&gt;keep Kubernetes manifests portable&lt;/li&gt;
&lt;li&gt;avoid platform-specific lock-in for runtime behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Portability preserves strategic options as business needs change.&lt;/p&gt;
&lt;h3&gt;A platform that evolves with the business&lt;/h3&gt;
&lt;p&gt;Kubernetes supports continuous improvement of both the platform and the applications that run on it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;add new services through APIs and operators&lt;/li&gt;
&lt;li&gt;adopt new deployment patterns progressively&lt;/li&gt;
&lt;li&gt;update platform components without changing application code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes infrastructure evolution less risky.&lt;/p&gt;
&lt;h3&gt;Avoiding brittle architecture&lt;/h3&gt;
&lt;p&gt;A flexible platform reduces the tendency to build brittle, environment-specific solutions. Kubernetes encourages teams to adopt declarative infrastructure and reusable components.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;infrastructure defined as code&lt;/li&gt;
&lt;li&gt;shared service catalogs for common needs&lt;/li&gt;
&lt;li&gt;versioned configuration and rollout plans&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Business impact&lt;/h3&gt;
&lt;p&gt;Long-term agility is about being able to respond to new markets, new regulations, and new customer demands. Kubernetes gives companies a foundation that grows with them rather than needing frequent forks or rewrites.&lt;/p&gt;</content><category term="Cloud, DevOps"></category><category term="kubernetes"></category><category term="agility"></category><category term="strategy"></category></entry><entry><title>Hosting a Secure Static Website on AWS S3 using Terraform</title><link href="https://www.tighov.link/hosting-a-secure-static-website-on-aws-s3-using-terraform.html" rel="alternate"></link><published>2025-05-21T15:19:00+04:00</published><updated>2025-05-21T15:19:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2025-05-21:/hosting-a-secure-static-website-on-aws-s3-using-terraform.html</id><summary type="html">&lt;p&gt;In this article, I'll cover how to create a static website on AWS using Terraform&lt;/p&gt;</summary><content type="html">&lt;p&gt;By the time you finish reading this article, you will know how to get your static websites up and running securely on AWS using Terraform. This can be a very cost-effective way of hosting a website. I have 3 websites set up on AWS and in total, they cost me less than $5 a month.&lt;/p&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Before we get started you are going to need some basics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic knowledge of Terraform&lt;/li&gt;
&lt;li&gt;Terraform v1.11.4 installed&lt;/li&gt;
&lt;li&gt;AWS CLI installed&lt;/li&gt;
&lt;li&gt;AWS Credentials correctly configured on your machine.&lt;/li&gt;
&lt;li&gt;A purchased domain, I buy mine from AWS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I use awsume for switching between AWS accounts and it also sets up all the correct environment variables to work with Terraform. If you are on a Mac you can just use Homebrew to install what you need:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;brew install terraform awscli awsume
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Aim for this Terraform project&lt;/h3&gt;
&lt;p&gt;I use the same setup for all my static websites. This is what we are looking to achieve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Secure website hosted at &lt;code&gt;https://www.yourdomain.com/&lt;/code&gt; with a valid SSL certificate&lt;/li&gt;
&lt;li&gt;Requests to the insecure website &lt;code&gt;http://www.yourdomain.com/&lt;/code&gt; are redirected to &lt;code&gt;https://www.yourdomain.com/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Requests without the www subdomain (&lt;code&gt;https://yourdomain.com/&lt;/code&gt;) are redirected to &lt;code&gt;https://www.yourdomain.com/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Website set up with performance best practices to achieve a high score on &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;Google&lt;/a&gt; &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;PageSpeed&lt;/a&gt; and &lt;a href="https://gtmetrix.com/"&gt;GTMetrix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;S3 Static Website Infrastructure&lt;/h3&gt;
&lt;p&gt;Hosting a static website on S3 only requires a few components, we don't even need anything complicated like VPCs or security groups to get this set up.&lt;/p&gt;
&lt;p&gt;Once we are finished we are going to have the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;S3 bucket that hosts our website files for our www subdomain&lt;/li&gt;
&lt;li&gt;S3 bucket that serves as the redirect to our www subdomain (I will explain later)&lt;/li&gt;
&lt;li&gt;SSL wildcard certificate validated for our domain that automatically renews.&lt;/li&gt;
&lt;li&gt;CloudFront distribution for the www and non-www domain which is our CDN.&lt;/li&gt;
&lt;li&gt;Route 53 records pointed at our CloudFront distributions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="AWS Cloud design diagram" src="images/posts/static-website-on-aws-s3/s3_static_website_infrastructure.png" title="AWS Cloud"&gt;&lt;/p&gt;
&lt;h3&gt;Setting up our Terraform components&lt;/h3&gt;
&lt;p&gt;Now we are going to go through each of the files that make up our Terraform project with an explanation of what each of them is doing.&lt;/p&gt;
&lt;h3&gt;Creating a bucket to store state files&lt;/h3&gt;
&lt;p&gt;There is one bit of infrastructure that we are going to set up manually and that is the S3 bucket for storing the Terraform state files. You technically could set this up with another Terraform script but then you would still need to store the state file for that as well.&lt;/p&gt;
&lt;p&gt;In these examples, I have called this S3 bucket &lt;code&gt;yourdomain-tf&lt;/code&gt;. You will want to call yours something meaningful but as with all S3 buckets it needs to be globally unique.&lt;/p&gt;
&lt;p&gt;Once created you can give it the following policy, making sure you update the account ID and bucket name.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;{
  &amp;quot;Version&amp;quot;: &amp;quot;2012-10-17&amp;quot;,
  &amp;quot;Statement&amp;quot;: [
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Principal&amp;quot;: {
        &amp;quot;AWS&amp;quot;: &amp;quot;arn:aws:iam::1234567890:root&amp;quot;
      },
      &amp;quot;Action&amp;quot;: &amp;quot;s3:ListBucket&amp;quot;,
      &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::yourdomain-tf&amp;quot;
    },
    {
      &amp;quot;Effect&amp;quot;: &amp;quot;Allow&amp;quot;,
      &amp;quot;Principal&amp;quot;: {
        &amp;quot;AWS&amp;quot;: &amp;quot;arn:aws:iam::1234567890:root&amp;quot;
      },
      &amp;quot;Action&amp;quot;: [&amp;quot;s3:GetObject&amp;quot;, &amp;quot;s3:PutObject&amp;quot;],
      &amp;quot;Resource&amp;quot;: &amp;quot;arn:aws:s3:::yourdomain-tf/*&amp;quot;
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Feel free to change the AWS principal to restrict access to another user or group.&lt;/p&gt;
&lt;h3&gt;providers.tf&lt;/h3&gt;
&lt;p&gt;Terraform needs plugins called providers to interact with remote systems. In this case, we are only dealing with AWS but Terraform can also interact with other cloud services such as Azure and Google Cloud.&lt;/p&gt;
&lt;p&gt;This also acts as the main file for the Terraform configuration such as where to store our state files.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;required_version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~&amp;gt; 0.14&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;required_providers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hashicorp/aws&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;~&amp;gt; 3.0&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;backend&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s3&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;yourdomain-tf&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prod.tfstate&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;us-east-1&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aws&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;us-east-1&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;aws&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;acm_provider&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;us-east-1&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here we are specifying the version of Terraform that we are using as well as the version of the AWS provider. This is to ensure that any future breaking changes to Terraform or the AWS provider do not stop our scripts from working.&lt;/p&gt;
&lt;p&gt;The backend block specifies where your state file is going to be stored. The bucket should match the name of the bucket you created in the last step.&lt;/p&gt;
&lt;p&gt;I have set up 2 providers here. The first AWS provider is the default provider (as it has no alias), this is what we will be using for the majority of our components.&lt;/p&gt;
&lt;p&gt;The second AWS provider is specifically for the SSL certificate. These need to be created in us-east-1 for CloudFront to be able to use them.&lt;/p&gt;
&lt;p&gt;In this example, I am creating everything in N. Virginia us-east-1, make sure you update this for your targeted region.&lt;/p&gt;
&lt;h3&gt;variables.tf&lt;/h3&gt;
&lt;p&gt;In this file, we define the variables that we are going to use. In this project, we only need 3: domain_name, bucket_name, and common_tags.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;domain_name&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Name of the domain&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;region&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;The AWS region to create the bucket in.&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;common_tags&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Common tags you want applied to all components.&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We are going to use these 3 variables throughout the project.&lt;/p&gt;
&lt;h3&gt;terraform.tfvars&lt;/h3&gt;
&lt;p&gt;The tfvars file is used to specify variable values. These will need to be updated for your domain.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tighov.link&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;us-east-1&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;common_tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Project&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tighov.link&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;prod&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Owner&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;tighov.link.admin&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The common_tags will be added to all the resources we are creating. This is useful to distinguish the cost of projects in billing reports.&lt;/p&gt;
&lt;h3&gt;s3.tf&lt;/h3&gt;
&lt;p&gt;In this file, we are going to set up our S3 buckets. Technically you can put all the Terraform configuration in one file but I like to separate them into different components, it is just clearer this way.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www.${var.domain_name}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common_tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_cors_configuration&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket_cors&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;cors_rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allowed_headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Authorization&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Content-Length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allowed_methods&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;POST&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allowed_origins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https://www.${var.domain_name}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;max_age_seconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_ownership_controls&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;object_ownership&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BucketOwnerPreferred&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_public_access_block&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;block_public_acls&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;block_public_policy&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ignore_public_acls&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;restrict_public_buckets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_website_configuration&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket_website&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;index_document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;error_document&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;404.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_policy&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_bucket_policy&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;templates/s3-policy.json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www.${var.domain_name}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# S3 bucket for redirecting non-www to www.&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_ownership_controls&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;object_ownership&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BucketOwnerPreferred&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_public_access_block&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_bucket&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;block_public_acls&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;block_public_policy&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ignore_public_acls&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;restrict_public_buckets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_website_configuration&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_bucket_website&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;redirect_all_requests_to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;host_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www.${var.domain_name}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;https&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_s3_bucket_policy&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_bucket_policy&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;templatefile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;templates/s3-policy.json&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first S3 bucket is where we are going to host all our website files. At a minimum, you will need to upload an index.html and a 404.html file in this bucket once it has been created.&lt;/p&gt;
&lt;p&gt;The CORS settings are required so that the content length of our files is sent to CloudFront. Without this, not all our files will have gzip compression and will result in lower scores on &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;Google&lt;/a&gt; &lt;a href="https://developers.google.com/speed/pagespeed/insights/"&gt;PageSpeed&lt;/a&gt; and &lt;a href="https://gtmetrix.com/"&gt;GTMetrix&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The second S3 bucket is going to redirect any requests to the www version of your website.&lt;/p&gt;
&lt;p&gt;The template file mentioned gives read access to the bucket:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;{
&lt;span class="w"&gt;  &lt;/span&gt;&amp;quot;Version&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;2012-10-17&amp;quot;,
&lt;span class="w"&gt;  &lt;/span&gt;&amp;quot;Statement&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;[
&lt;span class="w"&gt;    &lt;/span&gt;{
&lt;span class="w"&gt;      &lt;/span&gt;&amp;quot;Sid&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;PublicReadGetObject&amp;quot;,
&lt;span class="w"&gt;      &lt;/span&gt;&amp;quot;Effect&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;Allow&amp;quot;,
&lt;span class="w"&gt;      &lt;/span&gt;&amp;quot;Principal&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;*&amp;quot;,
&lt;span class="w"&gt;      &lt;/span&gt;&amp;quot;Action&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;s3:GetObject&amp;quot;,
&lt;span class="w"&gt;      &lt;/span&gt;&amp;quot;Resource&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;arn:aws:s3:::&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/*&amp;quot;
&lt;span class="w"&gt;    &lt;/span&gt;}
&lt;span class="w"&gt;  &lt;/span&gt;]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;acm.tf&lt;/h3&gt;
&lt;p&gt;Next, we need to set up our SSL certificate. I have gone with email validation in this setup as it is by far the quickest method. When the certificate has been created by Terraform, AWS will send an email to the owner of the domain to approve the certificate request. The Terraform script will not complete until this has been done.&lt;/p&gt;
&lt;p&gt;Alternatively, I have left the code for DNS validation which can be uncommented if you don't have email set up.&lt;/p&gt;
&lt;p&gt;DNS validation requires the domain nameservers to already be pointing to AWS. However, you won't know the nameservers you need until after the NS Route 53 record has been created.&lt;/p&gt;
&lt;p&gt;Alternatively, you can follow the validation instructions from the ACM page for your domain and apply them to where your nameservers are currently hosted. DNS validation can take 30 minutes or more during which the Terraform script will still be running.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# SSL Certificate&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_acm_certificate&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ssl_certificate&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acm_provider&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;subject_alternative_names&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*.${var.domain_name}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;validation_method&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;EMAIL&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;#validation_method         = &amp;quot;DNS&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common_tags&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;lifecycle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;create_before_destroy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Uncomment the validation_record_fqdns line if you do DNS validation instead of Email.&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_acm_certificate_validation&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;cert_validation&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;acm_provider&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;certificate_arn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_acm_certificate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ssl_certificate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arn&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;#validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can see in the above script that I am using the acm_provider as we need the certificate to be created in us-east-1 for CloudFront to be able to use it.&lt;/p&gt;
&lt;h3&gt;cloudfront.tf&lt;/h3&gt;
&lt;p&gt;Now that we have done the S3 and SSL certificate we can look at creating the CloudFront distributions. We need to create 2, one for each S3 bucket.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# CloudFront distribution for main s3 site.&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_cloudfront_distribution&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www_s3_distribution&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;website_endpoint&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;origin_id&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;S3-www.${var.bucket_name}&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;custom_origin_config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;http_port&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;https_port&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;origin_protocol_policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http-only&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;origin_ssl_protocols&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;is_ipv6_enabled&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;default_root_object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;index.html&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www.${var.domain_name}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;custom_error_response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;error_caching_min_ttl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;error_code&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;response_code&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;response_page_path&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/404.html&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;default_cache_behavior&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allowed_methods&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HEAD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cached_methods&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HEAD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;target_origin_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;S3-www.${var.bucket_name}&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;forwarded_values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;viewer_protocol_policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;redirect-to-https&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;min_ttl&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31536000&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;default_ttl&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31536000&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;max_ttl&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31536000&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;compress&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;restrictions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;geo_restriction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;restriction_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;viewer_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;acm_certificate_arn&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_acm_certificate_validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cert_validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;certificate_arn&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ssl_support_method&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sni-only&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;minimum_protocol_version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.1_2016&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common_tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# CloudFront S3 for redirect to www.&lt;/span&gt;
&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_cloudfront_distribution&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root_s3_distribution&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_s3_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;website_endpoint&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;origin_id&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;S3-.${var.bucket_name}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;custom_origin_config&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;http_port&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;https_port&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;origin_protocol_policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http-only&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;origin_ssl_protocols&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.2&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;is_ipv6_enabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;aliases&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;default_cache_behavior&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;allowed_methods&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HEAD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cached_methods&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;HEAD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;target_origin_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;S3-.${var.bucket_name}&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;forwarded_values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;query_string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;cookies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Origin&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;viewer_protocol_policy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;allow-all&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;min_ttl&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;default_ttl&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;86400&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;max_ttl&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;31536000&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;restrictions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;geo_restriction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;restriction_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;viewer_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;acm_certificate_arn&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_acm_certificate_validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cert_validation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;certificate_arn&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ssl_support_method&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sni-only&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;minimum_protocol_version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TLSv1.1_2016&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common_tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first one is our main distribution for our www bucket and has compression enabled and the max cache time enabled. Any HTTP requests to this distribution will be redirected to HTTPS automatically.&lt;/p&gt;
&lt;p&gt;The second distribution has little caching as all it does is point to the S3 bucket that redirects to our www website.&lt;/p&gt;
&lt;h3&gt;route53.tf&lt;/h3&gt;
&lt;p&gt;Last but not least we need to create the Route 53 records. The code below assumes you don't already have a hosted zone set up for this domain.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_route53_zone&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;common_tags&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_route53_record&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root-a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_route53_zone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_s3_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root_s3_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosted_zone_id&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;evaluate_target_health&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aws_route53_record&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www-a&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_route53_zone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;www.${var.domain_name}&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_s3_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;domain_name&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;zone_id&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;aws_cloudfront_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;www_s3_distribution&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hosted_zone_id&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;evaluate_target_health&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is pretty clear what this file is doing, it simply sets up a record for www and non-www and points it to the respective CloudFront distributions.&lt;/p&gt;
&lt;h3&gt;Terraform command to deploy our infrastructure&lt;/h3&gt;
&lt;p&gt;With everything set up all we need to do now is to run the commands to deploy our infrastructure. You need to make sure your computer is set up with all the correct AWS credentials for these commands to work, I use &lt;a href="https://awsu.me/"&gt;awsume&lt;/a&gt; for this.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is going to install our providers and any other plugins we are using.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;terraform plan
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will show us what infrastructure has changed and what will be added.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;terraform apply
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, this command will run the plan and you will be prompted to type yes to apply the changes.&lt;/p&gt;
&lt;p&gt;During this process, you will be sent an email by AWS (probably to your equivalent of webmaster@yourdomain.com) to validate your AWS certificate. You need to do this otherwise your Terraform won't complete.&lt;/p&gt;
&lt;p&gt;Once your www S3 bucket has been created you will also need to upload your website files. You can do this using the AWS CLI. Just cd to the directory containing your files and run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;aws s3 sync . s3://www.yourdomain.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will upload the contents of the directory to your S3 bucket. Whenever you make changes to the files in your S3 bucket you need to invalidate the CloudFront cache.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;aws cloudfront create-invalidation --distribution-id E3EDVELPIKTLHJ --paths &amp;quot;/*&amp;quot;;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Where E3EDVELPIKTLHJ is the CloudFront ID associated with your www S3 bucket.&lt;/p&gt;
&lt;p&gt;If you are using AWS CLI V2, it is worth adding &lt;code&gt;export AWS_PAGER=""&lt;/code&gt; (Linux and Mac) or &lt;code&gt;setx AWS_PAGER ""&lt;/code&gt; (Windows) to the front of this command so that you don't need to manually exit the command after running. This is a slightly &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html#cliv2-migration-output-pager"&gt;annoying breaking change&lt;/a&gt; that the AWS team added.&lt;/p&gt;
&lt;p&gt;Lastly, you need to point your domain nameservers to use the AWS nameservers. You will find these in the NS record of your hosted zone in the AWS console.&lt;/p&gt;
&lt;p&gt;It can take 24 - 48 hours for DNS changes to propagate but I usually find things are working after 5 minutes. It likely depends on who your domain registrar is. I am using Namecheap (affiliate link) for all of mine.&lt;/p&gt;</content><category term="Software, Cloud"></category><category term="cloud"></category><category term="aws"></category><category term="staticwebsite"></category></entry><entry><title>Software Architecture</title><link href="https://www.tighov.link/software-architecture.html" rel="alternate"></link><published>2025-04-26T20:00:00+04:00</published><updated>2025-04-26T20:00:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2025-04-26:/software-architecture.html</id><summary type="html">&lt;p&gt;In this blog post I discuss what software architecture is and why it is so important&lt;/p&gt;</summary><content type="html">&lt;p&gt;Development of software systems often fails, in particular when development teams deal with larger, more complex systems. Throughout the last years I have analyzed the main reasons for these project failures, and most of them were related to software architecture problems.&lt;/p&gt;
&lt;p&gt;Every software-intensive system has a software architecture, but the question is whether this architecture has been created in a clean, systematic way or just as a random by-product of software development. The latter might not be too much of an issue for a very small system, but certainly is for large systems.&lt;/p&gt;
&lt;p&gt;In my experience, software architecture serves as the backbone of a high-quality system. But first of all, we need to understand what software architecture really means.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Software engineering is conducted as a sequence of decisions where software architecture deals with all the decisions that have a system-wide impact.&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Len Bass&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whenever you need to change one of these decisions, this change will affect many system parts. Software architecture comprises the functional core of the system as well as strategic qualities such as performance or security.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Software architecture is about everything costly to change&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Grady Booch&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Architecture-relevant decisions mostly involve systematic mapping of key requirements to software architecture. Only when done in a systematic way can development teams verify they implemented the key requirements correctly. Only when the software architecture is known and documented can it be adapted should some of the key requirements change or evolve. Software architecture is also the best way to understand an existing system as it defines and mainly shapes the "machinery" of a software-intensive system. Architecture also comprises key guidelines and design decisions such as which patterns or tactics to use for recurring problems, and how to deal with systemic issues such as fault management.&lt;/p&gt;
&lt;p&gt;A good example where bad architecture hurts is product lines, platforms, and ecosystems where the architecture defines a template that can be completed and refined to obtain a real product. Take Linux or Android as examples. If they had no sound, easy-to-understand architecture, they could not be evolved or adapted over time. Take Windows XP as an example where lack of good architecture caused the OS to erode and become unmaintainable after some years, which is why Microsoft completely designed a new architecture for Windows 7, 8, and 10.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you think good architecture is expensive, try bad architecture&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Brian Foote and Joseph Yoder&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Some organizations start appreciating the value of software architecture only when it is absent or widely unknown.&lt;/p&gt;
&lt;p&gt;People who deny the relevance of architecture should ask themselves whether they would build their home without architecture, have surgery by a doctor who has no plan, or fly in a plane that has not been designed with architecture as its foundation.&lt;/p&gt;
&lt;p&gt;In some companies, software architecture is of utter importance, especially for large or complex systems. It is important to have good software architects in a project. By significantly improving the value of software architecture and software architects, far fewer projects fail. It is essential to document the architecture and make sure there is no drift between implemented and conceived architecture.&lt;/p&gt;</content><category term="Software, Design"></category><category term="sw-arch"></category></entry><entry><title>Coding Anti-Patterns</title><link href="https://www.tighov.link/coding-anti-patterns.html" rel="alternate"></link><published>2025-02-28T21:01:00+04:00</published><updated>2025-02-28T21:01:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2025-02-28:/coding-anti-patterns.html</id><summary type="html">&lt;p&gt;In this blog post I explain what anti-patterns are and why some of our colleagues cannot stop using them&lt;/p&gt;</summary><content type="html">&lt;h4&gt;Why anti-patterns are important&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Anti-patterns are important for job security. You can use anti-patterns to obfuscate the code so much that nobody can understand it, and you will be the only person who can. Everyone in the team will ask, "How does it work?"&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Revenge – if you are a disgruntled employee or maybe you want to watch the world burn, then anti-patterns are an excellent way to do it. The reason is that many people will not approve code that is obviously bad. You need the code to look at least legitimate to get through code reviews. Anti-patterns have that certain quality where it looks like the code is legitimate and good, and yet it will turn the code base into absolute mush over time. This sort of damage to code health is essentially irreversible. It will take a lot of time and effort for people to refactor and make it cleaner.  &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Tips for creating anti-patterns&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create tons of functions. If you already have a function that is doing something, break it down into three or four other functions, and for each of those, break them down into other functions too. Soon the only way to read your code is to jump from function to function to function. It is essentially spaghetti code, and yet it is not going to look like it because everything is broken down into neat little functions, and you will be able to easily get this sort of code passed through code review. If anybody ever asks you why you are doing this, you could just say that you are making it more unit-testable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use as many one-liners and cryptic code as possible. If there are multiple lines of code, you can usually join them all together into a single line using, say, the &lt;code&gt;and&lt;/code&gt; or &lt;code&gt;or&lt;/code&gt; operator. I also love using bit manipulations; instead of using multiple booleans, you can combine them all into a single byte array and then do bit manipulation to figure out the boolean values. When people ask, you can just say that this is going to be more efficient.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Anytime there is an if statement, in the condition you put a double exclamation mark so you are taking the not-not of a value. Technically, this is more correct because it turns the value into an actual boolean before you compare it in the if statement. You can also put error checks all over the place and you can just say that they are there to guard your code against not only malicious users but potentially malicious developers as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use recursion. While we all know that any recursive function can be made iterative, the reverse is also true. You can take any iterative function and make it recursive as well. What you do is you just create a recursive function, add an extra parameter that is the iteration count, and you increment that each cycle. This essentially simulates a for loop.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content><category term="Software, Design"></category><category term="sw-arch"></category></entry><entry><title>Clean Code</title><link href="https://www.tighov.link/clean-code.html" rel="alternate"></link><published>2025-01-03T21:01:00+04:00</published><updated>2025-01-03T21:01:00+04:00</updated><author><name>Tigran Hovhannisyan</name></author><id>tag:www.tighov.link,2025-01-03:/clean-code.html</id><summary type="html">&lt;p&gt;In this blog post I talk about clean code and some quick tips to help in daily life of a software developer&lt;/p&gt;</summary><content type="html">&lt;h4&gt;Why clean code is important&lt;/h4&gt;
&lt;p&gt;Over the years I've learned something that I want to share with you. Some of us code in C++, Python, Bash, Scala, Go, etc., and these are very different languages. But there are some techniques and approaches that really apply across languages, and in this brown bag I am going to talk about these.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;So that might sound nice "&lt;em&gt;Clean Code&lt;/em&gt;". But "&lt;em&gt;I have a deadline, I don't have time for clean code...&lt;/em&gt;"
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So in software development we run into deadline pressure. Our project manager is telling us that we have to get this done by the end of the sprint. We are working hard, and the common outcome of this is the big ball of mud code—the fast and dirty code to get something done. We are asked to go faster, but what happens is, we actually end up going slower. There are more bugs we have to go back and fix. We are finding needles in haystacks. Getting the work done actually takes longer than if we had written clean code to begin with, slowly. An ounce of prevention is worth a pound of cure.&lt;/p&gt;
&lt;p&gt;&lt;img alt="alt text" src="images/posts/clean-code/clean-vs-dirty.jpg" title="Logo Title Text 1"&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"The ratio of time spent reading code versus writing is well over 10 to 1."
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So how do we know this? There have actually been studies done, watching actual programmers work, how they are spending their time. People are actually spending most of their time scrolling up and down in a file, looking for something. "No, it's not there..." Open another file: "Oh, it's not there either. Where is this thing I'm trying to fix?" The actual time we spend typing is a lot less than the time we spend just looking around. So if we take the time to make our code easy to read, we will make the code easier to write. This is a great quote:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"We like to think we spend our time power typing, but we actually spend most of our time staring into the abyss."&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Douglas Crockford, principal discoverer of JSON, creator of JSLint&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is what I was just talking about. We're spending a lot of our time fighting the messy code. So with that as an explanation as to why it's important,
I want to show quick tips for making our code clean.&lt;/p&gt;
&lt;h4&gt;Tips&lt;/h4&gt;
&lt;h5&gt;We are responsible for the quality of our code&lt;/h5&gt;
&lt;p&gt;Not our scrum masters, not our project managers. If we think about other professions like doctors, lawyers, and accountants, they all have professional standards that they adhere to. We don't go to the doctor and say "You know what doc, I'm in a hurry, why don't you just skip washing your hands." We don't go to our accountant and say "Why don't you just skip the double-entry bookkeeping? Why are you bothering with that, let's do it quick?" We have certain respect for people in these professions and respect how they work. So if we want to be treated as professionals we have to act like professionals. We have to be advocates for the quality of the code that we write. And advocate for doing it the right way and not accept the option to do it the wrong way. It's up to us to define what these professional standards are and it's not up to our clients nor our project managers.&lt;/p&gt;
&lt;h5&gt;Use meaningful names&lt;/h5&gt;
&lt;p&gt;When we are writing our code we should use meaningful names.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Clean code should read like well-written prose.&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Grady Booch&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For example with variables.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;d&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;//&lt;span class="w"&gt; &lt;/span&gt;elapsed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;days
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is an example of a variable name that is not very good. &lt;code&gt;d&lt;/code&gt;—what does that mean? We have a little comment, it tells us what it does, but once we start getting into the code, we are looking at all these variables with all these cryptic names. The mental translating we have to do going back and forth between some cryptic symbol and its actual meaning starts to get in our way of actually understanding the work we're trying to do. So here are some better names that actually tell us what the variable does.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;elapsed_time_in_days&lt;span class="p"&gt;;&lt;/span&gt;
daysSinceCreation&lt;span class="p"&gt;;&lt;/span&gt;
days_since_modification&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So if we look at variable names like this, those are nouns in our prose.&lt;/p&gt;
&lt;h5&gt;Write code that expresses intent&lt;/h5&gt;
&lt;p&gt;The verbs in our prose are our functions and our methods. The idea here is that we have method names, just like our variable names, that clearly explain what it's for. As we read the code, we can sort of understand what it's doing without even knowing the context. We can get a sense of what's going on, and we can do that without comments. So this will be kind of a controversial comment on comments:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;"Comments are often lies waiting to happen. Code should speak for itself whenever possible."
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what do I mean by this? Often, we write comments because the intention of the code isn't clear. So we think "okay, let's write a comment that will explain it." But when we create the comment we've now written something else that we have to maintain in addition to the code. What often happens, once people are working on a project they come in, they fix a bug, they update the code, maybe don't notice the comment, now the comment is wrong, and now it's a lie, and it's going to take a future developer down the wrong path. I'm not saying never write comments. Often they are important—for example, if we're dealing with a third-party API and need to explain some behavior we know we can't necessarily do that in the code. So there are actually good cases for writing comments. I'm not saying never use them. What I am saying is when we're about to write a comment, step back and think for a moment and think, you know, can I write code that expresses itself a little better and then maybe I don't have to write a comment.&lt;/p&gt;
&lt;h5&gt;Boy Scout Rule&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;Always leave code cleaner than you found it!
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The boy scout rule, in case of code, is leave the code better than we found it. The boy scouts leave the campsite better than they found it. So not only am I saying we should write clean code but if we're working on some existing code, take a few minutes and look at the surrounding code. &lt;strong&gt;"Can I improve a variable name? Can I break up a method that's too big?"&lt;/strong&gt; So instead of the common scenario where code just gets messier and messier over time, we can instead have code that gets cleaner and cleaner over time. This is possible and I've worked with people who have done it and it's a great way to work.&lt;/p&gt;
&lt;h5&gt;The Single Responsibility Principle&lt;/h5&gt;
&lt;p&gt;This is one of five principles created by Bob Martin, who actually wrote the book Clean Code. So the Single Responsibility Principle is the idea when we are talking about, say, a function or method, that it does one thing, it does it well, and it does it only. So what do we mean by that? A good way to think about it is if we're passing four or five arguments to a function that's probably doing more than one thing. If we think about all those arguments, we are now creating a matrix of possible outcomes that can be quite large and hard to debug, because there's so many things going on inside it. So that's a good way of getting familiar with this principle.
When it comes to methods with classes, what we're looking for is what's called &lt;strong&gt;cohesiveness&lt;/strong&gt;.
The idea is, most of the methods in the class are using most of the properties. If we have one subset of methods using half the properties and another subset of methods using the other half, we are probably doing more than one thing in that class. Maybe it actually needs to be two classes so they each have a clear conceptual responsibility. It's clear what they're doing when they have one responsibility as opposed to many.&lt;/p&gt;
&lt;h5&gt;Write Tests&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;"This code worked the other day"
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are really two kinds of tests. One type is called &lt;strong&gt;integration tests&lt;/strong&gt; which actually test the functionality, how a user will experience our code. These have saved us so many times when we have changed something over here and we have run the test and found that it broke something over there. It's much better if we find it with our tests than we figure out it after deployment or an angry customer finding it two weeks later.&lt;/p&gt;
&lt;p&gt;There are also &lt;strong&gt;unit tests&lt;/strong&gt;, which test our functionality in isolation. Test-driven development is a great way to do this when we first come up with a test and then write our code to pass the test. It leads to better design.&lt;/p&gt;
&lt;h5&gt;Independent Architecture&lt;/h5&gt;
&lt;blockquote&gt;
&lt;p&gt;"Software architectures are structures that support the use cases of the system...&lt;/p&gt;
&lt;p&gt;Frameworks are tools to be used, not architectures to be conformed to.&lt;/p&gt;
&lt;p&gt;-- &lt;cite&gt;Bob Martin&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So what is he talking about here? We can take a framework, so we can say that framework is a tool to be used, not an architecture to be conformed to. The idea here is that there are good practices that can be applied across different frameworks and languages. So for example, some plugins that we have written should be very clear from looking at the files and the variable names what functionality this plugin implements. We should be able, with a few changes, to take it outside of the framework and use it. Our connections to the framework aren't any greater than they need to be.&lt;/p&gt;
&lt;p&gt;So the use cases are clear in the plugin—for example, it's not sort of yelling at us that it is a plugin, it is yelling at us that it is a photo rating service or something like that.&lt;/p&gt;
&lt;h5&gt;Practice, practice, practice&lt;/h5&gt;
&lt;p&gt;Musicians don't only play when they are on stage in front of an audience. Really the same applies to programming. We should do coding, POCs, learn new techniques when we are not performing for a customer. That's a way we can really improve our skills.&lt;/p&gt;</content><category term="Software, Design"></category><category term="sw-arch"></category></entry></feed>