<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Taka Saito</title>
    <description>The latest articles on DEV Community by Taka Saito (@roboword).</description>
    <link>https://dev.to/roboword</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2447332%2F27bba3f1-3996-4e5d-8898-6e06252af0d9.jpg</url>
      <title>DEV Community: Taka Saito</title>
      <link>https://dev.to/roboword</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roboword"/>
    <language>en</language>
    <item>
      <title>Demystifying the Man-Month (Part 2)</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Fri, 20 Dec 2024 00:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/demystifying-the-man-month-part-2-1ln</link>
      <guid>https://dev.to/roboword/demystifying-the-man-month-part-2-1ln</guid>
      <description>&lt;h2&gt;
  
  
  The Reality of System Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Starting from Zero
&lt;/h3&gt;

&lt;p&gt;The most remarkable thing about this company was that you were completely left to figure everything out by yourself.&lt;br&gt;
More precisely, there was nobody in the company who technically understood this work.&lt;br&gt;
Since there was no one who knew, I had no one to ask questions to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Background
&lt;/h3&gt;

&lt;p&gt;This project was the company's first contracted development work, and it was a control system project.&lt;br&gt;
Meanwhile, except for a few administrative staff and Team Leader T, all employees were dispatched workers specializing in accounting systems for banks and securities companies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Management Structure
&lt;/h3&gt;

&lt;p&gt;The development director was the president's younger brother, but he too specialized in accounting systems and knew nothing about control systems.&lt;br&gt;
He seemed capable and was often dispatched elsewhere. As an engineer, he had significant disagreements with his brother, the president, about management.&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Environment
&lt;/h3&gt;

&lt;p&gt;More troublesome was the fact that Team Leader T had no knowledge of the development environment - Unix, C language, and the proprietary UI system.&lt;br&gt;
The UI portion and most of the UI-related data processing were entirely dumped on me, while he only handled the final data processing parts that didn't involve UI.&lt;/p&gt;

&lt;p&gt;For technical matters, I could only rely on manuals and books.&lt;br&gt;
For business matters, I could only ask questions to the client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Life Before the Internet
&lt;/h3&gt;

&lt;p&gt;There was no internet like today. Even LANs weren't common back then.&lt;br&gt;
Can you imagine a time without mobile phones or email?&lt;br&gt;
That's why people wrote "XYZ" on station message boards back then.&lt;br&gt;
(City Hunter reference, for those who know)&lt;/p&gt;

&lt;p&gt;You'd occasionally see people on the Yamanote Line with shoulder bag-like mobile phones.&lt;br&gt;
Ah yes, the president had one of those too...&lt;/p&gt;

&lt;p&gt;[Rest of the content remains the same...]&lt;br&gt;
Ah yes, the president had one of those too...&lt;/p&gt;

&lt;h3&gt;
  
  
  Mysterious Meeting Members
&lt;/h3&gt;

&lt;p&gt;One day, the development director told me to come to work in a suit the next day.&lt;br&gt;
The next day, we headed to a meeting - the development director, Mr. T, myself, and six dispatched workers.&lt;/p&gt;

&lt;p&gt;Wait, what?&lt;/p&gt;

&lt;p&gt;These people were usually dispatched to major banks doing mainframe system maintenance.&lt;br&gt;
They rarely came to the office and only had experience with COBOL for mainframes...&lt;/p&gt;

&lt;p&gt;This whole situation seemed absurd.&lt;/p&gt;

&lt;p&gt;Nevertheless, the development director led all eight of us into the client's building.&lt;br&gt;
The contract structure for this work was explained as follows:&lt;/p&gt;

&lt;p&gt;[Major Electronics Manufacturer] → [Electronics Manufacturer Subsidiary] → [Prime Contractor (SI Company)] → [Subcontractor (Staffing Company)] → [Sub-subcontractor (My Part-time Workplace)]&lt;/p&gt;

&lt;p&gt;We were what's called a "third-tier subcontractor."&lt;br&gt;
The meeting was held at the Electronics Manufacturer Subsidiary's office.&lt;br&gt;
With sales representatives from the SI company and other subcontractors present, there were nearly 20 people.&lt;br&gt;
The development director introduced all eight of us as the development team, and we all bowed.&lt;/p&gt;

&lt;p&gt;"Pleased to work with you"&lt;/p&gt;

&lt;p&gt;Though I said this, I still couldn't understand the situation at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fictional Progress Charts
&lt;/h3&gt;

&lt;p&gt;A month later, a few days before the next meeting, the development director suddenly told me:&lt;/p&gt;

&lt;p&gt;"Make a progress chart for the next meeting."&lt;/p&gt;

&lt;p&gt;What on earth was that?&lt;/p&gt;

&lt;p&gt;I couldn't even picture the characters for it. I asked the development director.&lt;/p&gt;

&lt;p&gt;"What's a progress chart?"&lt;br&gt;
"It's a table with lines showing the progress status!"&lt;br&gt;
"What does 'progress' mean?"&lt;br&gt;
"It's how far along the work is!"&lt;/p&gt;

&lt;p&gt;He sketched out a progress tracking table, with functions and personnel listed on the vertical axis and the timeline from November to March on the horizontal axis.&lt;br&gt;
Then, although only Mr. T and I were actually working, the development director wrote in the names of everyone who had attended the previous meeting as responsible personnel.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Month&lt;/th&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;88/11&lt;/th&gt;
&lt;th&gt;12&lt;/th&gt;
&lt;th&gt;89/1&lt;/th&gt;
&lt;th&gt;2&lt;/th&gt;
&lt;th&gt;3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Saito&lt;/td&gt;
&lt;td&gt;Function A&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;Function B&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Function C&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;Function D&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Function E&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;E&lt;/td&gt;
&lt;td&gt;Function F&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;Function G&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mr. T&lt;/td&gt;
&lt;td&gt;Final Data Processing&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&lt;/td&gt;
&lt;td&gt;--&amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Still confused, I created the document by hand using a ruler and made copies.&lt;br&gt;
Of course, I included progress for all eight people.&lt;/p&gt;

&lt;p&gt;I was sent to the meeting alone. I answered all the detailed questions from the client.&lt;/p&gt;

&lt;p&gt;"Wow, it's impressive that someone so young can track everyone's progress in such detail."&lt;/p&gt;

&lt;p&gt;The client was impressed. Of course - I was doing all the development myself.&lt;/p&gt;

&lt;p&gt;"But this Mr. C seems to be behind schedule."&lt;br&gt;
"Well, that's because of this and that..."&lt;/p&gt;

&lt;p&gt;I desperately made excuses.&lt;/p&gt;

&lt;p&gt;"No, no, I'm not blaming you, Saito. I'm just pointing out that Mr. C is behind schedule."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's actually me.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point, I finally understood the man-month system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Truth About Man-Month Business
&lt;/h2&gt;

&lt;p&gt;This work was calculated in man-months.&lt;/p&gt;

&lt;p&gt;This meant the project was estimated at 40 man-months (8 people × 5 months).&lt;br&gt;
Though I never saw the estimate, I later heard from the prime contractor's representative that it was contracted for approximately $260,000.&lt;br&gt;
The company's accounting department also told me after I left that it was about $208,000.&lt;br&gt;
By the way, there was no consumption tax back then.&lt;/p&gt;

&lt;p&gt;However, in reality, only Mr. T and I (paid $13 per hour) were actually working.&lt;br&gt;
I was effectively doing 35 man-months of work. No, even more than that.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Burden Placed on a Novice
&lt;/h3&gt;

&lt;p&gt;The job included creating specifications and handling deliveries, but Mr. T didn't do any of this.&lt;br&gt;
The company really taught me nothing.&lt;br&gt;
Since Mr. T was even less comfortable with social interactions than I was, all client interactions were pushed onto me.&lt;br&gt;
With zero social skills or business manners, I was constantly scolded by clients.&lt;br&gt;
The company had strictly ordered me: "Never reveal that you're a student!"&lt;/p&gt;

&lt;p&gt;"How can you not know something this basic?"&lt;/p&gt;

&lt;p&gt;Yes, I'm sorry. I really am clueless about the business world.&lt;br&gt;
I wanted to ask them how many years of experience they thought I had.&lt;/p&gt;

&lt;p&gt;I had never written test specifications before, and no one taught me how, so I wrote them myself.&lt;br&gt;
All documentation had to be handwritten in those days. I created procedure documents for each test item and wrote in the results.&lt;br&gt;
There were hundreds of pages. The number of required test cases was based on the volume of code.&lt;br&gt;
For integration testing, I believe it was 40 items per 1,000 lines.&lt;br&gt;
I wrote 15,000 lines of code in three months, so I must have written 600 pages of test procedures.&lt;/p&gt;

&lt;p&gt;Later, I found my test specifications carelessly scattered at the client's office.&lt;br&gt;
I casually picked them up to look.&lt;/p&gt;

&lt;p&gt;After a few pages marked with red pencil corrections, someone had written "Idiot" and "Die."&lt;/p&gt;

&lt;p&gt;I felt tears welling up in my eyes.&lt;br&gt;
I had drafted these specifications with no real understanding of what I was doing.&lt;br&gt;
Without doubt, to the experienced client employees, the content was worse than garbage.&lt;br&gt;
I wondered who was really to blame...&lt;/p&gt;

&lt;p&gt;Nevertheless, the project was eventually completed successfully.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;With the profits from this project, the president treated himself to a Porsche.&lt;/p&gt;

&lt;p&gt;(End)&lt;/p&gt;

</description>
      <category>software</category>
      <category>management</category>
      <category>programming</category>
      <category>subcontracting</category>
    </item>
    <item>
      <title>Demystifying the Man-Month(Part1)</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Tue, 17 Dec 2024 07:02:58 +0000</pubDate>
      <link>https://dev.to/roboword/demystifying-the-man-monthpart1-41g9</link>
      <guid>https://dev.to/roboword/demystifying-the-man-monthpart1-41g9</guid>
      <description>&lt;h2&gt;
  
  
  A Junior Engineer's Tale from 1990s Japan 
&lt;/h2&gt;

&lt;p&gt;It might seem odd for me to discuss the "man-month rate" at this point in time. This has been a topic covered by prominent media like Nikkei Business for years. The most notable work, "The Mythical Man-Month: Essays on Software Engineering," published by Fred Brooks in 1975, remains relevant today. This speaks to how deeply rooted the challenges in software development are. Personally, "Peopleware: Productive Projects and Teams" by Tom DeMarco and Timothy Lister, which I read in my younger days, left a lasting impression. It's another excellent work that remains relevant in modern times. I strongly recommend young engineers read it.&lt;br&gt;
However, documenting my experiences might serve some purpose for future generations.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Junior Engineer in the World of System Development
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Encountering the Z-80 Assembler
&lt;/h3&gt;

&lt;p&gt;My entry into the IT industry began with Z-80 assembler work. At that time, it was just a part-time job, and the work was purely programming. In middle school, I had written programs on report paper, hand-assembled them while referring to code tables, and entered them using the MON command, only to watch them crash. For someone like me with only that experience, "macro assembler" was shocking. Variables could be used in assembly language. You didn't have to manage labels yourself. That's when I learned what professional programming was like.&lt;/p&gt;

&lt;p&gt;Eventually, this project fell through, and I only received partial payment. It was a control program for communication antenna equipment to be installed in mountainous areas, but the project was canceled, and it seemed we were cut off by the prime contractor. I still remember the expression on the president's face at that time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entering the World of UNIX Workstations
&lt;/h3&gt;

&lt;p&gt;A year later, during my leave of absence from university, I joined a company as a part-timer where we developed systems in C language on Unix workstations. What I learned at this company were the manners of being a working professional and the customs of the IT industry. As a student, I truly knew nothing. The media called my generation "shin-jinrui" (new breed). We were a generation that was lamented for not understanding common sense.&lt;/p&gt;

&lt;p&gt;It's amusing to think that generation is now turning 60, and we're talking about younger generations (laughs).&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Environment in the Early 1990s
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Learning to Be a Professional
&lt;/h3&gt;

&lt;p&gt;When asked to answer the phone at the company, I didn't even know how to do that. I was taught to say a formal greeting when answering, but I questioned why I should say such things to someone I didn't know. It took about a week until I could comfortably use proper business phone etiquette.&lt;/p&gt;

&lt;p&gt;Years later, when I started my own company and hired young people, I still remember being asked the same question.&lt;br&gt;
And then there was another thing I learned: the unit called "man-month."&lt;/p&gt;

&lt;h3&gt;
  
  
  Development Environment and Technical Stack
&lt;/h3&gt;

&lt;p&gt;Upon joining the company, I discovered several things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work was broadly divided into dispatched work and contracted projects&lt;/li&gt;
&lt;li&gt;Dispatched work dealt with financial systems, while contracted projects were for control systems&lt;/li&gt;
&lt;li&gt;Financial systems used COBOL or PL/I, while control systems used C language&lt;/li&gt;
&lt;li&gt;Financial systems ran on mainframes, while control systems operated on workstations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Until then, I had mainly programmed on personal computers and pocket computers. I occasionally used mainframes at university terminals, but that was mainly FORTRAN, with Prolog just for fun. At work, it was C language on workstations, and the Unix system I had dreamed of using.&lt;/p&gt;

&lt;p&gt;However, senior engineers stubbornly refused to use workstations, preferring to work on their PCs. I wondered how this could work, given the minimal compatibility between MS-DOS + MS-C and Unix + C.&lt;/p&gt;

&lt;p&gt;The reason was simple: senior engineers had never used Unix and didn't want to start. After all, the workstation manuals, when stacked, reached nearly 2 meters in height. They didn't want to bother reading all that.&lt;br&gt;
I struggled with those towering manuals while setting up the development environment. It was my first time using shell and vi. It took two days just to get the Makefile working.&lt;/p&gt;

&lt;p&gt;Come to think of it, my senior used MIFES, one of the popular text editors for MS-DOS in Japan at that time. Probably didn't want to learn vi. I believe they continued writing programs in their PC editor and transferring them to the workstation via floppy disk. Each transfer required character code conversion between MS-DOS and Unix systems - similar to how programs needed conversion between EBCDIC and ASCII when moving between IBM mainframes and other systems.&lt;/p&gt;

&lt;p&gt;My job was to create and debug programs according to the provided design documents, which were called functional design documents. I later learned that we were supposed to create detailed design documents from the functional design documents and then code from those. The detailed design documents turned out to be flowcharts, and I remember hand-drawing flowcharts from the source program before delivery. I recall receiving a special flowchart ruler from the prime contractor. That was quite handy.&lt;/p&gt;

&lt;p&gt;(To be continued)&lt;/p&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>unix</category>
      <category>assembler</category>
    </item>
    <item>
      <title>Why Japan's IT Industry Risks Being Left Behind - A Path to Individual Success</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Wed, 11 Dec 2024 19:47:40 +0000</pubDate>
      <link>https://dev.to/roboword/why-japans-it-industry-risks-being-left-behind-a-path-to-individual-success-3mda</link>
      <guid>https://dev.to/roboword/why-japans-it-industry-risks-being-left-behind-a-path-to-individual-success-3mda</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The Japanese IT industry stands at a critical crossroads. While Japan maintains its reputation for high-quality manufacturing and excellent social infrastructure, its IT sector faces unprecedented challenges. This analysis explores not only the industry's structural problems but also offers a practical path forward for individual IT professionals.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Shadow of the Past
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Persistence of the SES Model
&lt;/h3&gt;

&lt;p&gt;The System Engineering Service (SES) model, which treats engineers as interchangeable resources, continues to dominate Japan's IT landscape. This model, created during the bubble economy, persists despite fundamental changes in global technology development practices. Its continued existence reflects a deeper resistance to change within the industry, even as global competition intensifies and development methodologies evolve.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Requirements-Implementation Divide
&lt;/h3&gt;

&lt;p&gt;A particularly concerning trend is the separation between requirements definition and implementation. Companies increasingly focus on requirements definition for its higher profit margins while outsourcing actual implementation offshore. This creates a dangerous knowledge gap in the industry. Requirements specialists often lack practical implementation experience, leading to superficial documentation that fails to address technical complexities. The deterioration in the quality of requirements documents is striking, with some recent examples showing requirements definitions reduced to mere single-page documents. This situation severely limits opportunities for young engineers to gain hands-on development experience, creating a vicious cycle of declining technical expertise.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Cultural Quagmire
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Accountability Paradox
&lt;/h3&gt;

&lt;p&gt;Japanese business culture exhibits a peculiar contradiction in its approach to accountability. While there is an excessive emphasis on identifying responsible parties when problems occur, the same culture simultaneously discourages risk-taking and innovation. This paradoxical environment naturally leads to conservative decision-making, where avoiding mistakes takes precedence over pursuing innovative solutions. The harsh punishment of failure, combined with a system that dilutes real accountability for project success, creates a perfect storm that stifles creativity and progress.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Innovation Barrier
&lt;/h3&gt;

&lt;p&gt;The pervasive fear of failure, intertwined with traditional business practices, has erected significant barriers to innovation within the Japanese IT sector. Decision-makers consistently favor "proven" approaches over innovative solutions, regardless of their potential benefits. This conservative mindset has effectively suppressed the entrepreneurial spirit that once drove Japan's technological advancement. Furthermore, limited global collaboration opportunities, constrained by both language and cultural barriers, have isolated Japanese IT professionals from international best practices and emerging technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Skills Development Crisis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Erosion of Technical Expertise
&lt;/h3&gt;

&lt;p&gt;The industry's current structure has led to a critical erosion of technical skills among Japanese IT professionals. The emphasis on documentation and management over practical implementation has created a generation of engineers with limited hands-on coding experience. The lack of quality mentorship and practical training opportunities compounds this problem, as younger engineers have few chances to learn from experienced practitioners. The situation is particularly dire in the realm of modern development practices, where many Japanese IT professionals struggle to gain practical experience with cutting-edge technologies and methodologies.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Global Isolation Problem
&lt;/h3&gt;

&lt;p&gt;Japanese IT professionals increasingly find themselves isolated from global technology trends and communities. The limited participation in international open source communities has created a significant gap between Japanese developers and their global counterparts. This isolation is further exacerbated by language barriers that prevent meaningful participation in global technical discussions and collaboration opportunities. As a result, many Japanese IT professionals struggle to keep pace with rapidly evolving technology trends and best practices, creating a widening gap between domestic and international development standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reality of Government Initiatives
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Limits of Traditional Support
&lt;/h3&gt;

&lt;p&gt;While government support played a crucial role in Japan's past economic success, its effectiveness in the modern IT industry has proven limited. The traditional "convoy system" approach, which once successfully nurtured Japanese industries, is ill-suited for the rapid pace of technological change. Current government initiatives often prioritize form over substance, with bureaucratic requirements and budget-focused metrics taking precedence over genuine innovation and practical effectiveness. This misalignment between support structures and industry needs has resulted in numerous well-funded but ultimately ineffective programs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Education Gap
&lt;/h3&gt;

&lt;p&gt;The disconnect between formal education, government-sponsored training programs, and real-world industry needs has become increasingly apparent. Educational institutions and training programs often fail to provide the practical coding experience and exposure to modern development practices that professionals need to succeed in today's technology landscape. The absence of a strong continuous learning culture, combined with limited exposure to global development practices, leaves many Japanese IT professionals ill-equipped for the challenges of modern software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Path Forward: The Individual Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Breaking Free from Traditional Constraints
&lt;/h3&gt;

&lt;p&gt;Success in the modern IT industry increasingly requires individual initiative rather than reliance on traditional corporate or government structures. Forward-thinking professionals must take responsibility for their own technical growth, developing skills independently of company training programs. This includes building personal networks within global technical communities and embracing a mindset of continuous learning and adaptation. The most successful professionals are those who actively seek out opportunities to expand their technical capabilities beyond the constraints of traditional Japanese corporate structures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leveraging Japan's Advantages
&lt;/h3&gt;

&lt;p&gt;While pursuing global opportunities, IT professionals can benefit significantly from Japan's numerous strengths as a base of operations. The country's excellent infrastructure, strong social security system, and high quality of life provide a stable foundation for professional growth. The safe and stable environment offers an ideal platform from which to pursue global opportunities while maintaining a high standard of living. This combination of domestic stability and global opportunity creates a unique advantage for those willing to embrace it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Global Remote Work Opportunity
&lt;/h3&gt;

&lt;p&gt;The rise of remote work has created unprecedented opportunities for Japanese IT professionals. Working remotely for global companies while living in Japan offers access to higher compensation, exposure to cutting-edge technologies, and involvement in innovative projects. This approach provides a natural hedge against domestic market limitations while allowing professionals to maintain their preferred lifestyle. The ability to participate in global markets while enjoying Japan's high quality of life represents a particularly attractive path forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Steps for Success
&lt;/h2&gt;

&lt;p&gt;The path to success in the global IT market requires a deliberate and sustained effort to develop both technical and communication skills. Technical excellence must be pursued through hands-on coding experience, participation in open source projects, and mastery of modern development tools and practices. Equal emphasis must be placed on developing English language proficiency and cross-cultural communication skills, as these are essential for meaningful participation in global technology communities.&lt;/p&gt;

&lt;p&gt;Furthermore, career strategy must evolve beyond traditional employment models. Successful professionals increasingly focus on value creation and building relationships with international clients and employers. This approach requires maintaining flexibility in work arrangements and actively seeking out companies and projects that offer remote work opportunities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The challenges facing Japan's IT industry are deeply structural and unlikely to change quickly. However, individual professionals need not wait for systemic change to create successful careers. By taking personal initiative to develop global capabilities while leveraging Japan's quality of life advantages, IT professionals can forge fulfilling careers that transcend traditional constraints.&lt;/p&gt;

&lt;p&gt;The future belongs to those who can effectively bridge the gap between Japan's stable environment and global opportunities. While this path requires courage, initiative, and a willingness to step outside traditional career trajectories, it offers a viable route to professional growth and success in an increasingly global technology landscape. The time has come for Japanese IT professionals to take control of their own destiny, embracing the challenges and opportunities of the global market while maintaining the benefits of life in Japan.&lt;/p&gt;

</description>
      <category>japan</category>
      <category>career</category>
      <category>remote</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Dark Side of Japan's Early 1990s Software Development - Young Engineers as Disposable Resources</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Tue, 10 Dec 2024 20:27:51 +0000</pubDate>
      <link>https://dev.to/roboword/the-dark-side-of-japans-early-1990s-software-development-young-engineers-as-disposable-resources-ghc</link>
      <guid>https://dev.to/roboword/the-dark-side-of-japans-early-1990s-software-development-young-engineers-as-disposable-resources-ghc</guid>
      <description>&lt;p&gt;Recently, I've been hearing many young engineers say, "I only do design work, with no implementation experience." This highlights one of the major challenges facing today's IT industry in Japan.&lt;/p&gt;

&lt;p&gt;Implementation is crucial.&lt;/p&gt;

&lt;p&gt;In Japan, there has long been a tendency to equate "coders" with "programmers" while looking down on programming as a profession. There was even a time when programmers were expected to transition to System Engineers after just two years of experience due to low pay rates. While this was problematic in itself, I fortunately took a different path, having opportunities to work with brilliant programmers worldwide. I've even met true geniuses in the field.&lt;/p&gt;

&lt;p&gt;I hope my experiences can help young engineers seeking to forge their path in implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memories of a Brutal Workplace
&lt;/h2&gt;

&lt;p&gt;My career spans from consulting to operations - what we now call a full-cycle, full-stack engineer. I've experienced DevOps too. But of course, it all started with programming.&lt;/p&gt;

&lt;p&gt;This was during the transition from the Showa to Heisei era, when TV commercials boldly asked, "Can you fight for 24 hours!?" It was a time that allowed me to experience numerous challenging situations.&lt;/p&gt;

&lt;p&gt;How challenging?&lt;/p&gt;

&lt;p&gt;Let me share one example from when the bubble economy burst. I still remember a shocking conversation with a staff member at a large corporation where I was temporarily assigned:&lt;/p&gt;

&lt;p&gt;"Mr. Saito, I'm quitting today. Thank you for everything."&lt;/p&gt;

&lt;p&gt;"Oh, really?"&lt;/p&gt;

&lt;p&gt;"Yes, I wasn't feeling well, got some tests done, and the doctor warned me to quit immediately due to concerning internal organ readings..."&lt;/p&gt;

&lt;p&gt;He was tall, fair-skinned, and what we'd now call "handsome" - I believe he was part Northern European. He continued:&lt;/p&gt;

&lt;p&gt;"Actually, before this job, I was a host at a host club."&lt;/p&gt;

&lt;p&gt;"Really?"&lt;/p&gt;

&lt;p&gt;"But this job is tougher than being a host..."&lt;/p&gt;

&lt;p&gt;What kind of system development environment could be tougher than working as a host, where you're expected to drink champagne like water?&lt;/p&gt;

&lt;h2&gt;
  
  
  Contract Relations and System Structure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Contract Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk9469b6f3zbrap5en14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnk9469b6f3zbrap5en14.png" alt="Contract Flow" width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  System Overview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr0b0lpfqv4mk1p0igba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjr0b0lpfqv4mk1p0igba.png" alt="System Overview" width="800" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inadequate Development Environment
&lt;/h2&gt;

&lt;p&gt;The development environment for this project was so poor that it made work extremely inefficient. Without enough PCs capable of compilation for everyone, we had to write code on old PCs, copy it to development laptops via floppy disks, and then compile and link (make). Terms like "build" and "deploy" didn't exist back then - well, maybe Turbo-C used "Build"... Either way, it was so bad that I brought my newly purchased EPSON PC-486 (desktop) and color monitor (CRT) from home to the workplace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bizarre Development Environment
&lt;/h2&gt;

&lt;p&gt;The most perplexing aspect was designing the system while debugging it. This was before the word "agile" even existed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o0fefjzyp5sru8kd1u5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8o0fefjzyp5sru8kd1u5.png" alt="System Development Model" width="655" height="664"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Engineers would create rough specifications, immediately program them, and jump straight into integration testing. Naturally, errors were rampant. Reviews? Non-existent. Who even understood the complete specifications?&lt;/p&gt;

&lt;p&gt;"So-and-so quickly put together a demo version, showed it to the client, who said 'This is fine! Just tweak it a bit and you can release it soon!' And that's how development started haphazardly. Then they ran short on people, so we were brought in, but we'd never written C before, so we're reading introductory books while trying to write programs, and we just can't do it..."&lt;/p&gt;

&lt;p&gt;What kind of situation is this?&lt;/p&gt;

&lt;h2&gt;
  
  
  Bizarre Team Composition and Development Language
&lt;/h2&gt;

&lt;p&gt;While this system was being developed using MS-C on MS-DOS, most programmers only knew COBOL. Why was such a development team assembled? The shocking reason: the prime contractor's president declared, "C and COBOL start with the same letter, so they must be similar," and assigned young COBOL programmers to the project.&lt;/p&gt;

&lt;h3&gt;
  
  
  C Language and COBOL
&lt;/h3&gt;

&lt;p&gt;C language, which can directly manipulate memory, and COBOL, which specializes in business logic, are fundamentally different.&lt;/p&gt;

&lt;h4&gt;
  
  
  C Language
&lt;/h4&gt;

&lt;p&gt;A low-level language that enables efficient programming through direct memory manipulation using pointers and structures. Historically, many struggled with understanding pointers, making it a "cheat" language mastered only by those who could overcome the pointer barrier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Memory manipulation example&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Memory at %p contains %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  COBOL
&lt;/h4&gt;

&lt;p&gt;A business-oriented language specialized for processing large volumes of records with English-like syntax. I remember a colleague who boasted, "You only need to know 'MOVE', 'GOTO', and 'PERFORM' to code in COBOL!"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IDENTIFICATION DIVISION.
PROGRAM-ID. SALES-REPORT.
WORKING-STORAGE SECTION.
01 TOTAL-SALES PIC 9(8)V99.
PROCEDURE DIVISION.
    PERFORM UNTIL END-OF-FILE
       READ SALES-FILE
       ADD SALE-AMOUNT TO TOTAL-SALES
    END-PERFORM.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Did the Crisis End?
&lt;/h2&gt;

&lt;p&gt;We managed to create massive amounts of code and meet the release deadline. However, the system frequently froze at the service counter. Hiding behind a pillar, I watched reception staff angrily calling the development room, silently apologizing in my heart.&lt;/p&gt;

&lt;p&gt;Nevertheless, we managed to fix the bugs and achieve stable operation within a week. Midway through, my contract was changed from the prime contractor to direct with the manufacturer, but I didn't want to continue with this project, so I left at a convenient stopping point. The reason? Simply because I was young, the manufacturer's payment regulations meant I could only receive half the estimated amount at most. However, having a direct contract with the manufacturer was good for my reputation, and I didn't want to leave before achieving stable operation, so I stayed until then. While equal pay for equal work is advocated today, such concepts didn't exist back then.&lt;/p&gt;

&lt;h3&gt;
  
  
  Salary Situation Symbolizing Japan's IT Industry Decline
&lt;/h3&gt;

&lt;p&gt;At the time, my hourly rate was 8,500 yen (about $73 at 1990 exchange rates). In contrast, in 2024, similar work typically pays around 5,000 yen ($33) per hour.&lt;/p&gt;

&lt;p&gt;Why have wages decreased despite over 30 years of technological advancement and inflation? This dramatic wage difference symbolizes the decline of Japan's IT industry. In markets like the United States, experienced engineers can earn over $200 per hour. Meanwhile, Japan continues to be eroded by what's called the "Lost 30 Years" of deflation, affecting wages and economic vitality.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First AI Boom and Prolog
&lt;/h2&gt;

&lt;p&gt;By the way, are you familiar with Prolog? It was a celebrated language during the first AI boom of the 1980s. A declarative language that builds programs by defining rules of logic and inference, it was considered proficient at AI-like processing for drawing conclusions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight prolog"&gt;&lt;code&gt;&lt;span class="c1"&gt;% Define family relations and deduce grandparents&lt;/span&gt;
&lt;span class="ss"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;john&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;mary&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;mary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;bob&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="ss"&gt;grandparent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:-&lt;/span&gt; &lt;span class="ss"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;Z&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
&lt;span class="c1"&gt;% Can automatically answer "john is bob's grandparent?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Characterized by the ":-" symbol for defining rules, as a novice, I couldn't grasp Prolog's potential and couldn't imagine it being practical. However, the concept of "describing rules" would prove useful in my later work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Muscle-Headed Management
&lt;/h2&gt;

&lt;p&gt;In autumn 1988, at a certain company's new building unveiling ceremony, I was shocked by the president's (or chairman's) smug speech:&lt;/p&gt;

&lt;p&gt;"This is the era of Prolog! Programs can be written in one-tenth the code compared to COBOL! We will develop all our systems in Prolog!"&lt;/p&gt;

&lt;p&gt;Switching everything to Prolog just because it requires one-tenth the coding... What?&lt;/p&gt;

&lt;h2&gt;
  
  
  Vendors Who Grew by Consuming Engineers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Switch everything to Prolog because it's 10 times more productive than COBOL&lt;/li&gt;
&lt;li&gt;C and COBOL start with the same letter, so they must be similar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such simplistic thinking was incredibly muscle-headed, short-sighted, and disregarding of human rights... Programmers and SEs are human beings, not commodities or disposable tools.&lt;/p&gt;

&lt;p&gt;Back then, and even now, software vendor management is dominated by those with sales backgrounds. These vendors are essentially dispatch companies or human trafficking businesses, willing to do anything for sales. While this might be the essence of sales, the consequences invariably fall on the development team, and I believe this has come full circle to affect today's Japan.&lt;/p&gt;

&lt;p&gt;I spent just a month and a half at that chaotic workplace. During that time, half the development staff quit like falling dominoes. Some suffered physical breakdowns, others mental illness. I still remember leaving the site before the building locked down, looking at the lights of the Fukutoshin Line construction site from the taxi, heading home with indescribable feelings. How many companies grew large by crushing and consuming the bodies and minds of countless young people?&lt;/p&gt;

&lt;p&gt;Those who would now be called "corporate slaves" were then called "corporate warriors." Because toxic work environments were the norm, there wasn't even a term for "black companies" (exploitative employers). Those who survived were considered excellent human resources. This is the mindset of today's 50+ generation. I was once one of them too.&lt;/p&gt;

&lt;p&gt;As represented by BIG Motor, haven't those stuck with their Heisei-era success experiences continued their Showa-era methods even in the Reiwa era?&lt;/p&gt;

&lt;p&gt;Couldn't this be considered one factor that has effectively reduced the working population and shaped today's Japan?&lt;/p&gt;

&lt;p&gt;The president or chairman of a certain company proudly declared on stage:&lt;/p&gt;

&lt;p&gt;"We hire 400 people every year!"&lt;/p&gt;

&lt;p&gt;But their total employee count hadn't changed in 10 years. A senior colleague muttered under his breath.&lt;/p&gt;

</description>
      <category>career</category>
      <category>programming</category>
      <category>culture</category>
      <category>japan</category>
    </item>
    <item>
      <title>Requirements Engineering: A Practical Approach from 30 Years of Industry Experience</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Mon, 09 Dec 2024 20:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/requirements-engineering-a-practical-approach-from-30-years-of-industry-experience-5108</link>
      <guid>https://dev.to/roboword/requirements-engineering-a-practical-approach-from-30-years-of-industry-experience-5108</guid>
      <description>&lt;p&gt;Having handled dozens of requirements engineering projects throughout my career, I've developed a unique approach that differs from conventional methods. I'd like to share these insights and compare them with traditional approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  IT Is Not Just About Technology
&lt;/h2&gt;

&lt;p&gt;One of the greatest lessons from my 30 years in this field is this: &lt;strong&gt;IT systems cannot succeed on IT knowledge alone&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every industry operates under its own unique conditions, and IT solutions are akin to tailoring a suit for each business. However, not every situation requires a tailored suit. Many IT vendors, driven by profit motives, often sell complex "business suits" to clients who might just need casual wear.&lt;/p&gt;

&lt;p&gt;Consider this real-world example: An IT vendor once recommended a meal ticket vending machine for an izakaya (Japanese pub). This completely misses the nature of izakaya dining, where customers typically place multiple additional orders throughout their stay. A tablet ordering system would have been more appropriate. This mismatch occurred because the vendor prioritized making a quick sale over thoroughly understanding the client's business operations - a common pitfall in IT implementation projects. This case clearly shows how understanding business operations is crucial for proper system selection.&lt;/p&gt;

&lt;p&gt;This principle has guided me to prioritize practical, business-aligned solutions over purely technical implementations. It's a philosophy that underscores my consulting and systems design work.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Approach to Requirements Gathering
&lt;/h2&gt;

&lt;p&gt;My requirements gathering process begins with stakeholder interviews. Through careful organization of client needs and objective evaluation, unnecessary requirements are filtered out. Additionally, I incorporate potentially necessary requirements while comprehensively examining everything from development to operational methods, creating proposal-level documentation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 1: Iterative Requirements Gathering Process&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijavlqvjv685zv7vyn08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijavlqvjv685zv7vyn08.png" alt="Iterative Requirements Gathering Process" width="800" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This flowchart illustrates our systematic approach to requirements gathering, emphasizing continuous evaluation and refinement.&lt;/p&gt;

&lt;p&gt;This process actively utilizes methods such as SWOT analysis. Sometimes, the analysis concludes that an IT system isn't necessary at all. In such cases, I might suggest operational improvements instead, incorporating a consulting perspective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world Digital Transformation Decisions: A Case Study
&lt;/h2&gt;

&lt;p&gt;Let's examine a hypothetical example: A small retail shop with an elderly owner and predominantly senior customers, processing about 20 transactions daily with an average purchase value of $15. While digital transformation might seem appealing, a deeper analysis is necessary.&lt;/p&gt;

&lt;p&gt;Through stakeholder interviews and operational analysis, the conclusion was that introducing a cashless payment system would not provide significant productivity gains. Instead, we recommended minor adjustments to cash handling processes. This highlights an essential truth: sometimes, &lt;strong&gt;not implementing IT solutions is the best decision&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Approach to Requirements Specification
&lt;/h2&gt;

&lt;p&gt;In requirements specification, I conduct additional interviews as needed. Similar to requirements gathering, this involves organizing and evaluating requirements, but with emphasis on setting appropriate performance targets based on business scale and operational metrics (target revenue, access numbers, etc.). Operational costs are prioritized, with detailed examination of system configuration and operational methods.&lt;/p&gt;

&lt;p&gt;For documentation, I primarily use tools like &lt;strong&gt;PlantUML&lt;/strong&gt; and &lt;strong&gt;Mermaid&lt;/strong&gt;. These tools enable efficient, text-based diagram creation, making them ideal for agile workflows and integration with version control systems like Git. Additionally, they align seamlessly with Markdown and AI-driven documentation processes.&lt;/p&gt;

&lt;p&gt;Commonly used diagrams include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use Case Diagrams&lt;/strong&gt;: For visualizing user interactions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sequence Diagrams&lt;/strong&gt;: For understanding processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Component Diagrams&lt;/strong&gt;: For system architecture visualization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Industry Parallels and Future Outlook
&lt;/h2&gt;

&lt;p&gt;The system development industry shares similarities with real estate, particularly regarding monetary incentives and sales approaches. This understanding has led me to focus on budget-conscious and scale-appropriate requirements engineering.&lt;/p&gt;

&lt;p&gt;In recent years, I've incorporated AI into my workflow, treating it as another perspective rather than an absolute authority. In my consulting and system development practice, I effectively use AI to analyze various data sources including interview transcripts, company information, and existing system documentation to refine requirements. This comprehensive analysis helps identify patterns, potential gaps, and opportunities that might be missed in traditional requirements gathering. However, ultimate decisions still require human judgment and deep understanding of the business context.&lt;/p&gt;

&lt;p&gt;While currently operating independently, I share these experiences through blogs to benefit younger engineers, emphasizing that requirements engineering demands understanding &lt;strong&gt;business fundamentals&lt;/strong&gt; beyond technical aspects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Finding the optimal IT solution requires more than technical expertise - it demands the integration of business owner insights and operational staff perspectives. The key is not to implement the most advanced technology, but to find the most appropriate solution for each specific context.&lt;/p&gt;

&lt;p&gt;I encourage readers to apply this comprehensive approach in their own projects. Remember: Sometimes the best technical solution might be no technical solution at all. What matters most is understanding the real needs of your business and its stakeholders.&lt;/p&gt;

&lt;p&gt;This mindset, combined with modern tools like AI and systematic requirements engineering processes, can help ensure that your IT implementations truly serve their intended purpose and deliver lasting value.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>requirements</category>
      <category>consulting</category>
      <category>digitaltransformation</category>
    </item>
    <item>
      <title>Understanding and Preventing Email Spoofing Through DMARC Reports: A Technical Analysis</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Fri, 06 Dec 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/understanding-and-preventing-email-spoofing-through-dmarc-reports-a-technical-analysis-1jk</link>
      <guid>https://dev.to/roboword/understanding-and-preventing-email-spoofing-through-dmarc-reports-a-technical-analysis-1jk</guid>
      <description>&lt;p&gt;After implementing email authentication for my domain, I started receiving DMARC reports. These reports contain vital information about email authentication status and potential security issues. This article examines the contents of these reports and discusses the importance of email security enhancement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing DMARC Reports: Unexpected Discoveries
&lt;/h2&gt;

&lt;p&gt;Despite sending only 1-2 emails per week, I received DMARC reports at a higher frequency. Here's an analysis of one such report:&lt;/p&gt;

&lt;h3&gt;
  
  
  Report Analysis
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Report Metadata:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Organization: docomo.ne.jp&lt;/li&gt;
&lt;li&gt;Report ID: 0fa82be0508dfbf0734d46e8472e525e&lt;/li&gt;
&lt;li&gt;Date Range: September 26-27, 2024&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Published Policy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain: aqz.jp&lt;/li&gt;
&lt;li&gt;DKIM Configuration: s (strict)&lt;/li&gt;
&lt;li&gt;SPF Configuration: r (relaxed)&lt;/li&gt;
&lt;li&gt;DMARC Policy: none&lt;/li&gt;
&lt;li&gt;Policy Application Rate: 100%&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Identified Issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple IP addresses sending emails (e.g., 49.72.81.163, 49.64.241.80)&lt;/li&gt;
&lt;li&gt;DKIM and SPF failures across all records&lt;/li&gt;
&lt;li&gt;SPF results showing "permerror" (permanent error)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evaluation Results:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All messages show disposition as "none" due to DMARC policy settings&lt;/li&gt;
&lt;li&gt;No actual restrictions applied due to "none" policy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Investigation of Spoofing Attempts
&lt;/h2&gt;

&lt;p&gt;Further investigation of the source IPs revealed concerning patterns:&lt;/p&gt;

&lt;h3&gt;
  
  
  IP Analysis Results
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Network Attribution: China Telecom network&lt;/li&gt;
&lt;li&gt;Geographic Location: Jiangsu Province, China&lt;/li&gt;
&lt;li&gt;Network Range: 49.64.0.0 - 49.95.255.255&lt;/li&gt;
&lt;li&gt;Contact Information:

&lt;ul&gt;
&lt;li&gt;Abuse Contact: &lt;a href="mailto:anti-spam@chinatelecom.cn"&gt;anti-spam@chinatelecom.cn&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Technical Contact: &lt;a href="mailto:jsipmanager@163.com"&gt;jsipmanager@163.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The analysis indicates unauthorized use of the domain for sending emails, potentially compromising domain reputation and security.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comprehensive Protection Strategies
&lt;/h2&gt;

&lt;p&gt;Here are detailed steps to protect domains, especially those not actively used for email:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. SPF Record Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Record Type: TXT
Host Name: @
Content: v=spf1 -all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration prevents all email sending from the domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. DMARC Policy Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Record Type: TXT
Host Name: _dmarc.(domain-name)
Content: v=DMARC1; p=reject; rua=mailto:your-email@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This setting rejects emails failing SPF and DKIM authentication and sends reports to your email.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Additional Security Measures
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;DKIM Configuration (optional but recommended)&lt;/li&gt;
&lt;li&gt;Deactivation of Mail Servers&lt;/li&gt;
&lt;li&gt;Regular Monitoring through DMARC Reports&lt;/li&gt;
&lt;li&gt;Domain Registration Maintenance&lt;/li&gt;
&lt;li&gt;Registrar Lock Implementation&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Technical Implementation Guidelines
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Access DNS Records through your domain registrar or DNS hosting provider&lt;/li&gt;
&lt;li&gt;Add necessary TXT records for SPF and DMARC&lt;/li&gt;
&lt;li&gt;Allow 24-48 hours for DNS propagation&lt;/li&gt;
&lt;li&gt;Verify settings using online SPF/DMARC checker tools&lt;/li&gt;
&lt;li&gt;Monitor DMARC reports for unauthorized use&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This analysis reveals the critical importance of domain security and email authentication. Even domains not actively used for email communication can be targets for spoofing attempts. Implementing proper security measures through SPF, DKIM, and DMARC is essential for protecting domain reputation and preventing unauthorized use.&lt;/p&gt;

&lt;p&gt;Regular monitoring and maintenance of these security measures ensure continued protection against evolving email spoofing threats. The investment in proper domain security contributes not only to individual domain protection but also to the overall security of email communication on the Internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dmarc.org/documentation/" rel="noopener noreferrer"&gt;DMARC Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.openspf.org/SPF_Record_Syntax" rel="noopener noreferrer"&gt;SPF Record Syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tools.ietf.org/html/rfc6376" rel="noopener noreferrer"&gt;DKIM Protocol Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>security</category>
      <category>email</category>
      <category>cybersecurity</category>
      <category>domain</category>
    </item>
    <item>
      <title>Strengthening Email Security: A Comprehensive Guide to SPF, DKIM, and DMARC Implementation</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Wed, 04 Dec 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/strengthening-email-security-a-comprehensive-guide-to-spf-dkim-and-dmarc-implementation-3cm5</link>
      <guid>https://dev.to/roboword/strengthening-email-security-a-comprehensive-guide-to-spf-dkim-and-dmarc-implementation-3cm5</guid>
      <description>&lt;p&gt;Email security has become increasingly critical in today's digital landscape. With Google's recent announcement about stricter security requirements for Gmail, understanding and implementing email authentication protocols is more important than ever. This article explores three key technologies that form the foundation of modern email security: SPF, DKIM, and DMARC, with detailed UML diagrams to illustrate the implementation and authentication processes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Components
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SPF (Sender Policy Framework)
&lt;/h3&gt;

&lt;p&gt;SPF serves as the first line of defense in email authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Verifies that the sending mail server is authorized to send emails for a specific domain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt;: Domain owners publish a list of authorized email servers in DNS records&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function&lt;/strong&gt;: Receiving servers check if the sending IP address matches the authorized list&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DKIM (DomainKeys Identified Mail)
&lt;/h3&gt;

&lt;p&gt;DKIM provides cryptographic verification of email content:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Ensures email content hasn't been tampered with during transmission&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Sending servers add a digital signature to email headers&lt;/li&gt;
&lt;li&gt;The signature is created using a private key&lt;/li&gt;
&lt;li&gt;A corresponding public key is published in DNS records&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Function&lt;/strong&gt;: Receiving servers validate the signature using the public key&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  DMARC (Domain-based Message Authentication, Reporting, and Conformance)
&lt;/h3&gt;

&lt;p&gt;DMARC coordinates and enforces security policies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Purpose&lt;/strong&gt;: Provides instructions for handling authentication failures and generates reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implementation&lt;/strong&gt;: Domain owners publish policies specifying how to handle failed authentications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Function&lt;/strong&gt;: 

&lt;ul&gt;
&lt;li&gt;Integrates results from SPF and DKIM checks&lt;/li&gt;
&lt;li&gt;Enforces domain owner's preferences for handling suspicious emails&lt;/li&gt;
&lt;li&gt;Delivers reports about authentication failures&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation Process
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites and Setup
&lt;/h3&gt;

&lt;p&gt;Before implementing these security measures, several preparations are required. The following use case diagram illustrates the setup process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44cxt7g1zjfuv365gi95.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F44cxt7g1zjfuv365gi95.png" alt="Prerequisites and Setup" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication Process Overview
&lt;/h3&gt;

&lt;p&gt;The email authentication process involves multiple actors and systems. This use case diagram shows the relationships and interactions:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fads6vcc808iid9cfds4o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fads6vcc808iid9cfds4o.png" alt="Authentication Process" width="800" height="704"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Detailed Authentication Flow
&lt;/h3&gt;

&lt;p&gt;The following sequence diagram provides a detailed view of the authentication process:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffqvl26i0h0j18f0xsa9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fffqvl26i0h0j18f0xsa9.png" alt="Authentication" width="800" height="887"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Maintenance
&lt;/h2&gt;

&lt;p&gt;To maintain effective email security:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Regularly monitor DMARC reports&lt;/li&gt;
&lt;li&gt;Analyze authentication failures&lt;/li&gt;
&lt;li&gt;Adjust policies based on observed patterns&lt;/li&gt;
&lt;li&gt;Update authorized sender lists as needed&lt;/li&gt;
&lt;li&gt;Rotate DKIM keys periodically&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing SPF, DKIM, and DMARC is crucial for organizations that want to ensure reliable email delivery and protect their domain reputation. The UML diagrams provided in this article should help technical teams understand the implementation process and authentication flow in detail. While the initial setup requires careful planning and technical expertise, the long-term benefits in terms of security and deliverability make it a worthwhile investment.&lt;/p&gt;

&lt;p&gt;Remember that email security is not a one-time setup but requires ongoing monitoring and maintenance. Regular review of authentication reports and policy adjustments will help maintain the effectiveness of these security measures over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;RFC 7208 - Sender Policy Framework (SPF)&lt;/li&gt;
&lt;li&gt;RFC 6376 - DomainKeys Identified Mail (DKIM)&lt;/li&gt;
&lt;li&gt;RFC 7489 - Domain-based Message Authentication, Reporting, and Conformance (DMARC)&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>security</category>
      <category>email</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Fighting with Redirects: A Journey of Astro Site Migration</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Mon, 02 Dec 2024 18:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/fighting-with-redirects-a-journey-of-astro-site-migration-591a</link>
      <guid>https://dev.to/roboword/fighting-with-redirects-a-journey-of-astro-site-migration-591a</guid>
      <description>&lt;p&gt;During the migration of a website to Astro, I encountered significant challenges with URL redirects, particularly when dealing with Cloudflare Pages and Google Search Console. This article details the technical hurdles and solutions discovered while implementing redirects for a site with over 1000 legacy URLs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Context
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Framework: Astro&lt;/li&gt;
&lt;li&gt;Hosting: Cloudflare Pages&lt;/li&gt;
&lt;li&gt;Tools: Google Search Console&lt;/li&gt;
&lt;li&gt;Key File: &lt;code&gt;_redirects&lt;/code&gt; configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;After migrating from WordPress to Astro, I needed to redirect numerous URLs from the old structure &lt;code&gt;/blog/post/[slug]&lt;/code&gt; to the new structure &lt;code&gt;/post/[slug]&lt;/code&gt;. While this seems straightforward, the implementation revealed several complexities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inconsistent behavior with trailing slashes&lt;/li&gt;
&lt;li&gt;Wildcard matching limitations&lt;/li&gt;
&lt;li&gt;Cloudflare Pages' specific redirect rules&lt;/li&gt;
&lt;li&gt;Caching issues affecting redirect testing&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Different Approaches Tried
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Using Wildcards
&lt;/h3&gt;

&lt;p&gt;Initial attempt using wildcards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/blog/post/*  /post/:splat  301
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach failed because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URLs with trailing slashes were redirected to &lt;code&gt;/post/*/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The 301 status code caused unexpected behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Using Path Parameters
&lt;/h3&gt;

&lt;p&gt;Second attempt using path parameters:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/blog/post/:slug  /post/:slug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This partially worked:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/blog/post/005&lt;/code&gt; correctly redirected to &lt;code&gt;/post/005/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/blog/post/005/&lt;/code&gt; incorrectly redirected to &lt;code&gt;/post/*/&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Combined Approach
&lt;/h3&gt;

&lt;p&gt;Attempted to handle both cases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/blog/post/:slug /post/:slug
/blog/post/:slug/:page /post/:slug/:page
/blog/post/* /post/:splats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This still didn't provide consistent behavior across all URL patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;After experimenting with various patterns and configurations, the most reliable solution was to explicitly list each redirect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/blog/post/article-1 /post/article-1
/blog/post/article-2 /post/article-2
# ... and so on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this approach might seem less elegant than using wildcards or parameters, it provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Predictable behavior&lt;/li&gt;
&lt;li&gt;Easy troubleshooting&lt;/li&gt;
&lt;li&gt;Clear mapping for Google Search Console&lt;/li&gt;
&lt;li&gt;No issues with trailing slashes&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Learnings
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;URL Pattern Matching Complexity&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wildcards (&lt;code&gt;*&lt;/code&gt;) and path parameters (&lt;code&gt;:slug&lt;/code&gt;) behave differently&lt;/li&gt;
&lt;li&gt;Trailing slashes can significantly impact redirect behavior&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cloudflare Pages Specifics&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;301&lt;/code&gt; status code is optional in &lt;code&gt;_redirects&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Single wildcard limitation per rule&lt;/li&gt;
&lt;li&gt;Cache clearing may be necessary during testing&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Best Practices&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test redirects with and without trailing slashes&lt;/li&gt;
&lt;li&gt;Verify redirects in both development and production&lt;/li&gt;
&lt;li&gt;Use Google Search Console to confirm proper redirection&lt;/li&gt;
&lt;li&gt;Sometimes, explicit mapping is better than pattern matching&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;While pattern-based redirects might seem more maintainable, there are cases where explicit URL mapping is the most reliable solution. When dealing with SEO and legacy URLs, the priority should be ensuring consistent and correct behavior, even if it means writing more configuration code.&lt;/p&gt;

&lt;p&gt;There's a Japanese proverb that perfectly encapsulates this experience: "Isogaba maware" (急がば回れ) - literally meaning "when in a hurry, take the long way round." In software development, as in life, sometimes the seemingly longer, more methodical approach proves to be the most efficient solution in the end. While pattern matching and wildcards promised a quick fix, the explicit mapping approach, though more time-consuming initially, provided the most reliable and maintainable solution.&lt;/p&gt;

&lt;p&gt;Remember: The most elegant solution isn't always the most practical one. In critical infrastructure like URL redirects, reliability should take precedence over conciseness.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>cloudflare</category>
      <category>redirects</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Single Quote Curse: When AI Mistook an MDX Front Matter Issue for a YAML Bug</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Fri, 29 Nov 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/the-single-quote-curse-when-ai-mistook-an-mdx-front-matter-issue-for-a-yaml-bug-20e3</link>
      <guid>https://dev.to/roboword/the-single-quote-curse-when-ai-mistook-an-mdx-front-matter-issue-for-a-yaml-bug-20e3</guid>
      <description>&lt;h2&gt;
  
  
  The Error
&lt;/h2&gt;

&lt;p&gt;While running &lt;code&gt;npm run build&lt;/code&gt; in my Astro project, I encountered this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;[&lt;/span&gt;ERROR] &lt;span class="o"&gt;[&lt;/span&gt;types] &lt;span class="o"&gt;[&lt;/span&gt;GenerateContentTypesError] astro &lt;span class="nb"&gt;sync command &lt;/span&gt;failed to generate content collection types: can not &lt;span class="nb"&gt;read &lt;/span&gt;a block mapping entry&lt;span class="p"&gt;;&lt;/span&gt; a multiline key may not be an implicit key
  Hint:
    Check your src/content/config.&lt;span class="k"&gt;*&lt;/span&gt; file &lt;span class="k"&gt;for &lt;/span&gt;typos.
  Error reference:
    https://docs.astro.build/en/reference/errors/generate-content-types-error/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Asking AI for Help
&lt;/h2&gt;

&lt;p&gt;I turned to AI for help, and interestingly, it immediately assumed this was a YAML syntax issue:&lt;/p&gt;

&lt;p&gt;"It looks like there's a YAML formatting issue in your &lt;code&gt;src/content/config.*&lt;/code&gt; file. Common causes include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incorrectly indented multiline strings&lt;/li&gt;
&lt;li&gt;Missing colons after keys&lt;/li&gt;
&lt;li&gt;Improper use of YAML syntax"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After 30 minutes of following AI's YAML-focused suggestions with no success, I decided to try solving it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Traditional Way
&lt;/h2&gt;

&lt;p&gt;When searching online, I found others encountering the same error. All discussions were in English, but notably, no one had posted a solution. The key realization was that &lt;strong&gt;no one seemed to know how to fix it&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;With no clear direction, I decided to run &lt;code&gt;npm run dev&lt;/code&gt; just to see what would happen. This time, I got a more detailed error message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  reason: &lt;span class="s1"&gt;'can not read a block mapping entry; a multiline key may not be an implicit key'&lt;/span&gt;,
  mark: Mark &lt;span class="o"&gt;{&lt;/span&gt;
    name: null,
    buffer: &lt;span class="s1"&gt;'\n'&lt;/span&gt; +
      &lt;span class="s2"&gt;"title: 'Example Title&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; +
      &lt;span class="s2"&gt;"description: 'A long description that continues...'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      // ... rest of front matter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there it was. &lt;strong&gt;A missing closing single quote in the MDX front matter.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97gou78v463ydye2yzb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F97gou78v463ydye2yzb2.png" alt="The embarrassingly simple bug" width="800" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's why the &lt;code&gt;description&lt;/code&gt; field was highlighted in orange in my editor. I had completely overlooked this basic syntax error.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI's Current Limitations
&lt;/h2&gt;

&lt;p&gt;This experience revealed an interesting limitation of AI: it misdiagnosed the problem entirely. Instead of recognizing this as a simple MDX front matter syntax error, it went down a rabbit hole of YAML configuration troubleshooting. Why? Probably because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The error message contained the phrase "block mapping entry", which is YAML terminology&lt;/li&gt;
&lt;li&gt;The error referenced &lt;code&gt;config.*&lt;/code&gt; files, which are often YAML files&lt;/li&gt;
&lt;li&gt;AI's training data likely contains many instances of YAML-related errors with similar messages&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;AI can be misled by error messages that seem familiar but have different root causes&lt;/li&gt;
&lt;li&gt;Sometimes AI's pattern matching can lead it down the wrong path entirely&lt;/li&gt;
&lt;li&gt;Basic syntax errors can masquerade as complex configuration issues&lt;/li&gt;
&lt;li&gt;When AI can't find the exact solution in its training data, it might try to force-fit the problem into a familiar pattern&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next time you get a cryptic error message, remember that the solution might be simpler than what AI suggests, and might not even be related to what the AI thinks is the problem.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>ai</category>
      <category>mdx</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Mysterious Display in Astro: Unraveling the Secrets of the Development Environment</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Tue, 26 Nov 2024 15:00:00 +0000</pubDate>
      <link>https://dev.to/roboword/mysterious-display-in-astro-unraveling-the-secrets-of-the-development-environment-42ne</link>
      <guid>https://dev.to/roboword/mysterious-display-in-astro-unraveling-the-secrets-of-the-development-environment-42ne</guid>
      <description>&lt;h2&gt;
  
  
  Static Site Generator Journey
&lt;/h2&gt;

&lt;p&gt;For years, I've been working on WordPress projects, but recently I switched to Astro. With AI assistance for customization, I thought I could create my own theme, but that was naive. TailwindCSS was new to me - I hadn't even used Bootstrap or Material Design before. I used to think CSS was solely for designers, not programmers. Thanks to AI, I can now design without needing a designer. I'm finally benefiting from modern development practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mysterious Display
&lt;/h2&gt;

&lt;p&gt;While developing with Astro, I suddenly noticed mysterious characters appearing in the top-left corner of my page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf4pre0zjmqefks81dim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnf4pre0zjmqefks81dim.png" alt="Mysterious Display" width="800" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These characters in the top-left corner change as you adjust the viewport width. At first, I panicked - was this a bug?&lt;/p&gt;

&lt;h2&gt;
  
  
  Breakpoint Indicator
&lt;/h2&gt;

&lt;p&gt;After investigation, I discovered this was a "breakpoint indicator" - a development tool for visually confirming Tailwind CSS and other responsive design framework breakpoints in Astro projects.&lt;/p&gt;

&lt;p&gt;Key features include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Displays the current viewport's breakpoint&lt;/li&gt;
&lt;li&gt;Updates dynamically as you resize the browser window&lt;/li&gt;
&lt;li&gt;Helps developers instantly verify responsive design implementations&lt;/li&gt;
&lt;li&gt;Only appears in development environment, not in production&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I initially considered an eyesore turned out to be a useful development tool that wouldn't appear in the production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Details
&lt;/h2&gt;

&lt;p&gt;Let's examine the actual implementation. Here's the content of &lt;code&gt;TwSizeIndicator.astro&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;---
// TwSizeIndicator.astro
---

{
    process.env.NODE_ENV === 'development' &amp;amp;&amp;amp; (
        &amp;lt;div class='fixed top-0 left-0 z-50 flex w-[30px] items-center justify-center bg-gray-200 py-[2.5px] text-[12px] uppercase text-black sm:bg-red-200 md:bg-yellow-200 lg:bg-green-200 xl:bg-blue-200 2xl:bg-pink-200'&amp;gt;
            &amp;lt;span class='block sm:hidden'&amp;gt;all&amp;lt;/span&amp;gt;
            &amp;lt;span class='hidden sm:block md:hidden'&amp;gt;sm&amp;lt;/span&amp;gt;
            &amp;lt;span class='hidden md:block lg:hidden'&amp;gt;md&amp;lt;/span&amp;gt;
            &amp;lt;span class='hidden lg:block xl:hidden'&amp;gt;lg&amp;lt;/span&amp;gt;
            &amp;lt;span class='hidden xl:block 2xl:hidden'&amp;gt;xl&amp;lt;/span&amp;gt;
            &amp;lt;span class='hidden 2xl:block'&amp;gt;2xl&amp;lt;/span&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code reveals several important points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;process.env.NODE_ENV === 'development'&lt;/code&gt; condition ensures it only appears in development&lt;/li&gt;
&lt;li&gt;Tailwind CSS classes set different background colors and display text for each breakpoint&lt;/li&gt;
&lt;li&gt;Combinations of &lt;code&gt;hidden&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt; classes show only the text for the current breakpoint&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  NODE_ENV Configuration
&lt;/h2&gt;

&lt;p&gt;Why does it only appear in development? This behavior is controlled by the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;npm run dev&lt;/code&gt;, &lt;code&gt;NODE_ENV&lt;/code&gt; is automatically set to &lt;code&gt;development&lt;/code&gt;. This is standard behavior in many Node.js frameworks and tools.&lt;/p&gt;

&lt;p&gt;Key points:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;npm run dev&lt;/code&gt; is widely used as a development command&lt;/li&gt;
&lt;li&gt;Many frameworks automatically set &lt;code&gt;NODE_ENV&lt;/code&gt; to &lt;code&gt;development&lt;/code&gt; when running the dev script&lt;/li&gt;
&lt;li&gt;Production commands like &lt;code&gt;npm run build&lt;/code&gt; or &lt;code&gt;npm run start&lt;/code&gt; typically set &lt;code&gt;NODE_ENV&lt;/code&gt; to &lt;code&gt;production&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Application behavior can be modified based on the &lt;code&gt;NODE_ENV&lt;/code&gt; value&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means the breakpoint indicator appears in the development environment using &lt;code&gt;npm run dev&lt;/code&gt; where &lt;code&gt;NODE_ENV&lt;/code&gt; is &lt;code&gt;development&lt;/code&gt;, but not in production where &lt;code&gt;NODE_ENV&lt;/code&gt; is &lt;code&gt;production&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: This may not work as expected with wrangler!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;What initially appeared as a mysterious display in Astro turned out to be the useful "breakpoint indicator." While it seemed intrusive at first, it's actually a valuable tool for implementing responsive design.&lt;/p&gt;

&lt;p&gt;The implementation cleverly combines Tailwind CSS and Astro features to create functionality that only works in the development environment. The use of the &lt;code&gt;NODE_ENV&lt;/code&gt; environment variable to achieve different behaviors in development and production environments is particularly interesting.&lt;/p&gt;

&lt;p&gt;This experience shows that frameworks and tools often contain hidden features designed to improve developer efficiency. When encountering new technology, understanding these mechanisms deeply can lead to more effective utilization.&lt;/p&gt;

</description>
      <category>astro</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Implementing Gmail API with Cloudflare Workers - Part 3: Implementation</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Sat, 23 Nov 2024 07:49:23 +0000</pubDate>
      <link>https://dev.to/roboword/implementing-gmail-api-with-cloudflare-workers-part-3-implementation-199f</link>
      <guid>https://dev.to/roboword/implementing-gmail-api-with-cloudflare-workers-part-3-implementation-199f</guid>
      <description>&lt;p&gt;In this article, I'll show you how to implement email sending functionality using Gmail API in Cloudflare Workers. This is part 3 of the series, focusing on the implementation details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Configure wrangler.toml
&lt;/h3&gt;

&lt;p&gt;First, set up your environment variables in &lt;code&gt;wrangler.toml&lt;/code&gt;. Store your service account key as an environment variable - never hardcode it in your source code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"contact-form"&lt;/span&gt;
&lt;span class="py"&gt;pages_build_output_dir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./dist"&lt;/span&gt;

&lt;span class="nn"&gt;[vars]&lt;/span&gt;
&lt;span class="py"&gt;ENVIRONMENT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"development"&lt;/span&gt;
&lt;span class="py"&gt;BCC_EMAIL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your-bcc@example.com"&lt;/span&gt;
&lt;span class="py"&gt;SERVICE_ACCOUNT_EMAIL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"xxxxxxxxxxxxx.iam.gserviceaccount.com"&lt;/span&gt;
&lt;span class="py"&gt;SERVICE_ACCOUNT_KEY&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your-private-key"&lt;/span&gt;
&lt;span class="py"&gt;IMPERSONATED_USER&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your-email@example.com"&lt;/span&gt;
&lt;span class="py"&gt;COMPANY_NAME&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Your Company Name"&lt;/span&gt;
&lt;span class="py"&gt;COMPANY_EMAIL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"contact@example.com"&lt;/span&gt;
&lt;span class="py"&gt;COMPANY_WEBSITE&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://example.com"&lt;/span&gt;
&lt;span class="py"&gt;EMAIL_SUBJECT&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Contact Form Submission"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Implement the Contact Form Handler
&lt;/h3&gt;

&lt;p&gt;Here's the complete implementation of the contact form handler (&lt;code&gt;contact-form.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;ENVIRONMENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;BCC_EMAIL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;SERVICE_ACCOUNT_EMAIL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;SERVICE_ACCOUNT_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;IMPERSONATED_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;COMPANY_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;COMPANY_EMAIL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;COMPANY_WEBSITE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;EMAIL_SUBJECT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isLocalhost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENVIRONMENT&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;conditionalLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLocalhost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ExecutionContext&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handleOptionsRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Only POST method is allowed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;405&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createEmailContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;emailContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Email sent successfully&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to send email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in fetch:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An unexpected error occurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;errorMessage&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isLocalhost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST, OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPANY_WEBSITE&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Methods&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST, OPTIONS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Access-Control-Allow-Headers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleOptionsRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Missing required fields&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailPattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[^\s&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;emailPattern&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createEmailContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;company&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;company&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;company&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

Thank you for contacting &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPANY_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.

● Inquiry Details:

&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;

---------

While we may not be able to respond to all inquiries,
we assure you that we read every message we receive.

Thank you for your interest in our company.

&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPANY_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;headersToArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;][]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;][]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;accessToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;validateEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`=?UTF-8?B?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;base64Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL_SUBJECT&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;?=`&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`=?UTF-8?B?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;base64Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPANY_NAME&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;?= &amp;lt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;COMPANY_EMAIL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;`&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bcc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BCC_EMAIL&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;emailParts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s2"&gt;`From: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;`To: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;`Subject: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s2"&gt;`Bcc: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;bcc&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MIME-Version: 1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type: text/plain; charset=UTF-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Transfer-Encoding: base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;base64Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;emailParts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.googleapis.com/gmail/v1/users/me/messages/send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Bearer &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;base64UrlEncode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="nf"&gt;conditionalLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`Gmail API Response Status: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;conditionalLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Gmail API Response Headers:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;headersToArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;responseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;conditionalLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Gmail API Response Body:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s2"&gt;`Failed to send email: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;statusText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Response: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Error in sendEmail:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&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;h3&gt;
  
  
  3. Key Features
&lt;/h3&gt;

&lt;p&gt;The implementation includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Form validation&lt;/li&gt;
&lt;li&gt;OAuth 2.0 token generation&lt;/li&gt;
&lt;li&gt;Gmail API integration&lt;/li&gt;
&lt;li&gt;CORS handling&lt;/li&gt;
&lt;li&gt;Environment-based configuration&lt;/li&gt;
&lt;li&gt;Error handling and logging&lt;/li&gt;
&lt;li&gt;Email content creation with proper encoding&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4. Important Technical Notes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Library Constraints&lt;/strong&gt;: Cloudflare Workers has limitations on libraries. You can't use native Node.js modules; you must write browser-compatible code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: The implementation uses service account authentication with JWT tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CORS&lt;/strong&gt;: The code includes proper CORS handling for both development and production environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Comprehensive error handling is implemented throughout the code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment Variables&lt;/strong&gt;: Variables are managed through Cloudflare's environment variable system.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5. Deployment and Testing
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Local Testing&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx wrangler pages dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Production Deployment&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;Environment variables are automatically synced from wrangler.toml&lt;/li&gt;
&lt;li&gt;Change ENVIRONMENT to 'production' after deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  6. Known Limitations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;VSCode debugger doesn't work with Pages Functions (unlike Workers)&lt;/li&gt;
&lt;li&gt;Environment variables management differs between Workers and Pages Functions&lt;/li&gt;
&lt;li&gt;Some Node.js modules and features are not available in the Workers runtime&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This implementation provides a secure and scalable way to send emails using Gmail API through Cloudflare Workers. The code is designed to be maintainable, secure, and production-ready, with proper error handling and environment-specific configurations.&lt;/p&gt;

&lt;p&gt;The complete source code can be found in the repository, along with detailed setup instructions from parts 1 and 2 of this series.&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>typescript</category>
      <category>gmail</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Implementing Gmail Sending with Cloudflare Workers - Development Guide</title>
      <dc:creator>Taka Saito</dc:creator>
      <pubDate>Tue, 19 Nov 2024 20:30:58 +0000</pubDate>
      <link>https://dev.to/roboword/implementing-gmail-sending-with-cloudflare-workers-development-guide-4844</link>
      <guid>https://dev.to/roboword/implementing-gmail-sending-with-cloudflare-workers-development-guide-4844</guid>
      <description>&lt;p&gt;This is Part 2 of a series on implementing Gmail sending with Cloudflare Workers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 1: Setup ✅&lt;/li&gt;
&lt;li&gt;Part 2: Development Environment (Current)&lt;/li&gt;
&lt;li&gt;Part 3: Implementation (Coming Soon)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;After setting up Gmail API access in Part 1, we'll now configure our development environment for Cloudflare Workers. This guide focuses on creating a robust development setup that works seamlessly with both Cloudflare Pages and Workers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Cloudflare Infrastructure
&lt;/h2&gt;

&lt;p&gt;Cloudflare operates on a globally distributed edge computing platform. When traffic increases, pages are replicated across these servers, and users are directed to the nearest server. This serverless architecture eliminates the need for managing your own servers, Docker containers, or Kubernetes clusters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare Workers and Pages
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workers Overview
&lt;/h3&gt;

&lt;p&gt;Cloudflare Workers are serverless functions that handle request processing. While Cloudflare Pages handles the frontend (static content), Workers manage backend operations like form processing and email sending.&lt;/p&gt;

&lt;h3&gt;
  
  
  Available Storage Options
&lt;/h3&gt;

&lt;p&gt;Workers can integrate with various Cloudflare storage solutions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;D1&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SQLite-based serverless SQL database&lt;/li&gt;
&lt;li&gt;Up to 10GB storage capacity&lt;/li&gt;
&lt;li&gt;30-day Time Travel feature&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;KV (Key-Value)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Globally distributed key-value store&lt;/li&gt;
&lt;li&gt;Optimized for edge reading&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Durable Objects&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent state management&lt;/li&gt;
&lt;li&gt;Ideal for distributed systems&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;R2&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3-compatible object storage&lt;/li&gt;
&lt;li&gt;Large file handling capability&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Hyperdrive&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL database connector&lt;/li&gt;
&lt;li&gt;Optimized connection pooling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Important Notes About Wrangler
&lt;/h2&gt;

&lt;p&gt;Recent changes to Wrangler's usage pattern require attention. Previously, Wrangler was typically installed globally, but the recommended approach has changed:&lt;/p&gt;

&lt;p&gt;Old method (not recommended):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; wrangler
wrangler init my-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New recommended method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create cloudflare@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This change provides better project isolation and version management.&lt;/p&gt;

&lt;h2&gt;
  
  
  Language Environment in Cloudflare Workers
&lt;/h2&gt;

&lt;p&gt;While Cloudflare Workers might appear similar to Node.js, there are important differences:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Node.js modules are not available&lt;/li&gt;
&lt;li&gt;Code must be browser-compatible&lt;/li&gt;
&lt;li&gt;TypeScript is supported, providing strong typing benefits&lt;/li&gt;
&lt;li&gt;Node.js is installed per project for development only&lt;/li&gt;
&lt;li&gt;Direct HTTP requests must be used instead of Node.js libraries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Understanding Cloudflare Pages Applications
&lt;/h2&gt;

&lt;p&gt;Cloudflare Pages Applications differ from traditional Workers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are fully integrated web applications running on the Cloudflare Pages platform&lt;/li&gt;
&lt;li&gt;Pages Functions extend this functionality through the &lt;code&gt;/functions&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;This integration allows for serverside processing (like email handling) directly within your Pages application&lt;/li&gt;
&lt;li&gt;No separate Worker deployment is needed when using Pages Functions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Development Environment Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create a Cloudflare account&lt;/li&gt;
&lt;li&gt;Connect your GitHub repository to Pages&lt;/li&gt;
&lt;li&gt;Configure deployment settings&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Project Structure Setup
&lt;/h3&gt;

&lt;p&gt;Create the following directory structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;your-project/
├── src/
│   └── pages/
│       └── index.astro
├── functions/
│   ├── contact-form.ts
│   └── tsconfig.json
├── public/
├── astro.config.mjs
├── package.json
└── wrangler.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;functions
&lt;span class="nb"&gt;touch &lt;/span&gt;functions/contact-form.ts functions/tsconfig.json wrangler.toml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Install Dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; typescript @cloudflare/workers-types
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Configure TypeScript
&lt;/h3&gt;

&lt;p&gt;Add to functions/tsconfig.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&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="nl"&gt;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lib"&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="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"types"&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="s2"&gt;"@cloudflare/workers-types"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sourceMap"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update project tsconfig.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&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="s2"&gt;"src/**/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&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="s2"&gt;"functions/**/*"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;The next article in this series will cover the implementation details, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating the email sending function&lt;/li&gt;
&lt;li&gt;Handling form submissions&lt;/li&gt;
&lt;li&gt;Error handling and validation&lt;/li&gt;
&lt;li&gt;Testing and deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Stay tuned for Part 3, where we'll bring everything together with the actual implementation.&lt;/p&gt;

</description>
      <category>cloudflare</category>
      <category>gmail</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
