未経験からエンジニア 奮闘記

未経験からエンジニアに自由に生きる途中

MENU

【golang】変数

概要・ポイント

  • 概要
    • 変数定義について
      • 基本的な変数定義
      • 定数
  • ポイント
    • varで変更可能な変数定義が可能
    • 型推論機能がある

内容

  • 変数定義

基本的な変数の定義は varで作成できる

package main

import "fmt"

func main() {
        var name string= "tanaka"
    fmt.Println("name: ", name)
        // => name: tanakaと出力される

        // 型が推論されて stringは不要
        var name = "yamada"
    fmt.Println("name: ", name)
        // => name: yamadaと出力される

        var a, b int = 1 ,2
    fmt.Println("a: ", a)
    fmt.Println("b: ", b)
        // => a: 1と出力される
        // => b: 2と出力される

        // varを両略可能
        
        fruit := "apple"
        fmt.Println("fruit: ", fruit)
        // =>fruit: appleと出力される
}


  • 定数

定数はmain関数の外にもかける。他の言語と同様で、変更は不可

package main

import (
    "fmt"
    "math"
)

const s string = "constant"

func main() {
    fmt.Println(s)

    const n = 500000000

    const d = 3e20 / n
    fmt.Println(d)

    fmt.Println(int64(d))

    fmt.Println(math.Sin(n))
}

感想

型推論の部分がTypescriptな雰囲気を感じました。 :=の省略記法は最初は慣れないですが、書いていると結構便利かも

参考

  • 参考サイト

www.spinute.org

www.spinute.org

【golang】 hello world

概要・ポイント

  • 概要
  • ポイント
    • goはパッケージ単位でコードを管理することが可能
    • go run xx.goで実行が可能
    • go build xx.goでバイナリファイルを作成して実行も可能

内容

  • コード go はパッケージ単位(関数単位)で実行が出来る様です。
// main.goファイル

// mainの場合は特別らしい。エントリポイントであることを認識させる
package main

// formatの略で、標準出力関数が利用できます
import "fmt"

func main() {
    fmt.Println("hello world")
}
  • 実行

コンパイルしないでもローカルであれば下記で実行可能

go run main.go

参考

  • mac で環境構築

zenn.dev

  • 参考サイト

www.spinute.org

Reactでスプレッド演算子を使ったデータ更新についてまとめてみました

Reactでデータを更新するときにスプレッド演算子をよく使うことがあります。今回は、その使い方と理由、具体的な使いどころをまとめてみました。

スプレッド演算子の使い方

まずは基本的な使い方をおさらいします。スプレッド演算子...)は、オブジェクトや配列のコピーを作るために使います。例えば、以下のように使います:

const originalArray = [1, 2, 3];
const newArray = [...originalArray, 4]; // [1, 2, 3, 4]

const originalObject = { a: 1, b: 2 };
const newObject = { ...originalObject, c: 3 }; // { a: 1, b: 2, c: 3 }

なんで使うのか?

スプレッド演算子を使う理由は、主にイミュータブルの原則に従うため です。Reactでは、状態(state)を直接変更しないようにするのが基本です。直接変更すると、Reactが変更を検知できなくて、UIが正しく更新されないことがあるからです。

イミュータブルなデータ構造を使うことで、Reactが状態の変更を正しく検知できるようにします。つまり、元のオブジェクトや配列をそのまま変更せず、新しいコピーを作ることで状態を更新するのです。

どんな時に使うか?

スプレッド演算子を使うタイミングは、主に以下のような場合です:

  1. 状態を更新するとき: 状態を更新するときは、元の状態をコピーして、新しい値を追加したり変更したりします。
   const [state, setState] = useState({ name: 'John', age: 30 });

   const updateAge = () => {
     setState(prevState => ({
       ...prevState,
       age: prevState.age + 1
     }));
   };
  1. 配列を操作するとき: 配列に新しい要素を追加したり、要素を削除したりするときにも使います。
   const [items, setItems] = useState([1, 2, 3]);

   const addItem = () => {
     setItems(prevItems => [...prevItems, 4]);
   };

   const removeItem = () => {
     setItems(prevItems => prevItems.filter(item => item !== 2));
   };

まとめ

スプレッド演算子を使うことで、Reactのイミュータブルの原則に従いながら、状態の更新や配列の操作をシンプルに行うことができます。元のデータを直接変更せず、新しいコピーを作ることで、Reactが変更を正しく検知してUIを更新できるようにするのです。

Reactでデータを扱うときは、スプレッド演算子を上手に使って、効率よくイミュータブルなデータ構造を保つようにしましょう。

初心者向け:useStateがなかったらJavaScriptでどうやって実装するか

はじめに

この記事では、ReactのuseStateフックを使わずに、JavaScriptでUIの状態管理を行う方法について説明します。useStateを使用することで状態管理が非常に簡単になりますが、初心者の方にとってその背後にある基本的な概念を理解することも重要です。ここでは、イベント処理を使ってUIを変更する方法と、useStateを使った方法の両方を紹介します。

サンプル

今回はサンプルとして、ボタンをクリックしたら文字が変わる実装を元に、従来のJSのでの実装と、useStateを利用を比較してみて行きたいと思います。

useStateがない場合の実装

まず、useStateを使わずにイベント処理でUIを変更するコードを見てみましょう。ここでは、ボタンをクリックするとテキストが変わるシンプルな例を使います。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>State Management without useState</title>
</head>
<body>
  <div id="app">
    <p id="text">初期テキスト</p>
    <button id="changeTextButton">テキストを変更</button>
  </div>

  <script>
    document.addEventListener('DOMContentLoaded', () => {
      const textElement = document.getElementById('text');
      const buttonElement = document.getElementById('changeTextButton');

      buttonElement.addEventListener('click', () => {
        textElement.textContent = '変更後のテキスト';
      });
    });
  </script>
</body>
</html>

この例では、ボタンがクリックされると、JavaScriptのイベントリスナーがテキストを変更します。useStateを使わずに、DOM操作だけでUIを更新しています。

useStateを利用したコード

次に、同じ機能をReactのuseStateフックを使って実装してみましょう。

import React, { useState } from 'react';

function App() {
  const [text, setText] = useState('初期テキスト');

  const handleChangeText = () => {
    setText('変更後のテキスト');
  };

  return (
    <div>
      <p>{text}</p>
      <button onClick={handleChangeText}>テキストを変更</button>
    </div>
  );
}

export default App;

こちらのコードでは、useStateを使って状態を管理しています。useStateは現在の状態とそれを更新する関数を返し、状態が変更されると自動的にUIが再レンダリングされます。

まとめ

useStateがない場合でも、イベント処理を使ってUIの状態を変更することは可能です。しかし、ReactのuseStateフックを使用することで、状態管理がよりシンプルで直感的になります。初心者の方は、まず基本的なJavaScriptによるDOM操作を理解し、その後でuseStateを使った状態管理に進むと、Reactの強力な機能をより深く理解できるでしょう。

単一方向バインディングと双方向バインディングの違いとメリット・デメリットを理解する

背景

最近、UIライブラリのOSS開発者の方と話していて、「双方向バインディングは避けたほうが良い」と聞いて、ちょっと興味が湧きました。そこで、単一方向バインディングと双方向バインディングの違いやメリット・デメリットについてまとめてみました。

単一方向バインディングと双方向バインディングのメリット・デメリット

単一方向バインディング

メリット:

  • シンプルでわかりやすい: データの流れが一方向なので、コードの追跡が簡単。
  • デバッグが容易: データの変更が予測しやすく、バグが発生した際に原因を見つけやすい。
  • パフォーマンス向上: データの変更が少ないため、無駄な再レンダリングが減る。

デメリット:

  • コードが冗長になる: 状態管理が複雑な場合、コード量が増える。
  • 双方向の連携が面倒: 双方向のデータ連携が必要な場合、手動での更新が必要。

双方向バインディング

メリット:

  • 直感的: フォーム入力など、ユーザーのアクションに対して即時に反応できる。
  • コードが短くなる: 自動でデータが同期されるため、コード量が減る。

デメリット:

  • デバッグが難しい: データの流れが複雑になり、バグの原因を特定しにくい。
  • パフォーマンスの低下: 頻繁なデータの変更により、レンダリングが多発しやすい。

ReactとAngularでのサンプルコードを見比べてみます

Reactでの単一方向バインディング

import React, { useState } from 'react';

const SingleWayBinding = () => {
  const [value, setValue] = useState('');

  const handleChange = (event) => {
    setValue(event.target.value);
  };

  return (
    <div>
      <input type="text" value={value} onChange={handleChange} />
      <p>{value}</p>
    </div>
  );
};

export default SingleWayBinding;

Reactの場合、valueが変更されると、再度レンダリングして新しい値を用いて、UIを変更してますよね。 これはデータ => UIの一方方向が実現できていると思います。 とても分かりやすいですね。

Angularでの双方向バインディング

// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, FormsModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

// app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  value: string = '';
}

// app.component.html
<div>
  <input [(ngModel)]="value" type="text" />
  <p>{{ value }}</p>
</div>

一方で、Angularの場合は、value(データ)を用いてUIを表示して、inputからvalueが更新されると、ReactのようにonChangeの関数などのでデータを更新せずともUIからデータを更新できてしまう仕組みになっています。 これは便利な部分もあると思うのですが、データが絡みあっているのでデバックがしずらく可能性がありそうですね。

まとめ

個人的には、Reactの単一方向バインディングの方がデータフローがシンプルでメンテナンスしやすいと感じました。特に大規模なアプリケーションでは、単一方向バインディングの方がバグを避けやすいかもしれません。
単一方向バインディングと双方向バインディングにはそれぞれメリットとデメリットがあります。ユースケースによってどちらが適しているかは異なるため、絶対に単一方向バインディングが良いというわけではありません。自分のプロジェクトに合った方法を選ぶことが大切です。

React Reduceの使い方をマスターしよう!

背景

JavaScriptreduceというメソッドは、存在は知っていても実際にどのような場面で使うのかがわかりにくいことがあります。私も以前はその一人でしたが、最近購入履歴のデータを加工してチャートに反映する機会があり、その時にreduceの便利さを実感しました。具体的には、Rechartsを使ってグラフを描くために、購入履歴データを集計する必要がありました。

jsのreduceの挙動

まず、reduceの基本的な挙動について説明いたします。reduceは配列を一つの値にまとめるための関数ですが、初期値(initialValue)が数字の場合とオブジェクトの場合で少し使い方が変わります。

初期値が数字の場合

例えば、配列内の数字の合計を求める場合は以下のようにします:

const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((acc, current) => acc + current, 0);
console.log(sum); // 10

ここで、accは累積値で、currentが現在の要素です。initialValueとして0を渡しているので、最初のaccは0からスタートします。

初期値がオブジェクトの場合

次に、初期値がオブジェクトの場合を見てみましょう。例えば、購入履歴をカテゴリごとに集計したい場合は以下のようになります:

const purchaseHistories = [
  { id: 1, amount: 100, category: { name: '外食' } },
  { id: 2, amount: 50, category: { name: '交際費' } },
  { id: 3, amount: 100, category: { name: 'Netflix' } },
  { id: 4, amount: 150, category: { name: '外食' } },
];

const categoryTotals = purchaseHistories.reduce((acc, history) => {
  const category = history.category.name;
  if (!acc[category]) {
    acc[category] = 0;
  }
  acc[category] += history.amount;
  return acc;
}, {});

console.log(categoryTotals);
// { '外食': 250, '交際費': 50, 'Netflix': 100 }

ここで、初期値として空のオブジェクト{}を渡しているため、各カテゴリの合計金額を計算することができます。

実際に利用した場面

次に、実際にどのように使ったかを見てみましょう。

上記のreduceを使って集計したデータを元に、Rechartsで画像の様なパイチャートを描きます。 以下のコードをご覧ください:

'use client'
import { Cell, Pie, PieChart, ResponsiveContainer } from 'recharts'

const COLORS = ['#0088FE', '#00C49F', '#FFBB28', '#FF8042']
const RADIAN = Math.PI / 180

interface CustomizedLabelProps {
  cx: number
  cy: number
  midAngle: number
  innerRadius: number
  outerRadius: number
  percent: number
  index: number
  name: string
  value: number
}

const renderCustomizedLabel = ({
  cx,
  cy,
  midAngle,
  innerRadius,
  outerRadius,
  percent,
  index,
  name,
  value,
}: CustomizedLabelProps) => {
  const radius = innerRadius + (outerRadius - innerRadius) * 0.5
  const x = cx + radius * Math.cos(-midAngle * RADIAN)
  const y = cy + radius * Math.sin(-midAngle * RADIAN)

  return (
    <text
      x={x}
      y={y}
      fill="white"
      textAnchor={x > cx ? 'start' : 'end'}
      dominantBaseline="central"
      fontSize="13px"
    >
      {`${name} ${(percent * 100).toFixed(0)}%`}
    </text>
  )
}

const purchaseHistories = [
  {id: 1, amount: 100 ,category: { name: '外食'}},
  {id: 2, amount: 50 ,category: { name: '交際費'}},
  {id: 3, amount: 100 ,category: { name: 'Netflix'}},
  {id: 4, amount: 150 ,category: { name: '外食'}},
]

const RechartPipeChart = () => {
  const groupByCategoryPurchaseHistories = () => {
    const categoryTotals = purchaseHistories.reduce(
      (acc: Record<string, number>, history) => {
        const category = history.category.name
        if (!acc[category]) {
          acc[category] = 0
        }
        acc[category] += history.amount
        return acc
      },
      {},
    )

    return Object.keys(categoryTotals).map((category) => ({
      name: category,
      value: categoryTotals[category],
    }))
  }

  const groupedData = groupByCategoryPurchaseHistories()

  return (
    <>
      <ResponsiveContainer width="100%" height={300}>
        <PieChart width={500} height={500}>
          <Pie
            data={groupedData}
            cx="50%"
            cy="50%"
            labelLine={false}
            label={({
              cx,
              cy,
              midAngle,
              innerRadius,
              outerRadius,
              percent,
              index,
            }) =>
              renderCustomizedLabel({
                cx,
                cy,
                midAngle,
                innerRadius,
                outerRadius,
                percent,
                index,
                name: groupedData[index].name,
                value: groupedData[index].value,
              })
            }
            outerRadius={150}
            fill="#8884d8"
            dataKey="value"
          >
            {groupedData.map((entry, index) => (
              <Cell
                key={`cell-${index}`}
                fill={COLORS[index % COLORS.length]}
              />
            ))}
          </Pie>
        </PieChart>
      </ResponsiveContainer>
    </>
  )
}

export default RechartPipeChart

ここでは、purchaseHistoriesreduceを使ってカテゴリごとに集計し、その結果をmapでRechartsが扱いやすい形に変換しています。これにより、購入履歴のデータを元にしたパイチャートを表示することができます。

まとめ

reduceは一見難しそうに見えますが、使い方を覚えるとデータを集計したり変換したりするのに非常に便利です。特に初期値をうまく設定することで、様々なデータの操作が可能になります。今回の例では、購入履歴のデータをカテゴリごとに集計してチャートに反映する方法をご紹介しましたが、他にも多くの場面で応用できますので、ぜひ試してみてください。

未経験からエンジニアに転職して質問に回答してみた

初めに簡単な自己紹介

最初に自己紹介 こんにちは!私は営業として3年働いた後、2ヶ月程プログラミングスクールに通い、事業会社への転職に成功しました。現在では正社員として2社の事業会社と受託開発で3年半程、フリーランスとして2年半程の経験があります。現在は週4日のフルリモートで月収75万円程で働いています。 週末は勉強、ゲーム、週末ワーケーションしたりしています。

よくある転職相談の内容に回答してみました

知り合いや、初めて知り合った人から転職相談をよく受けるので、よくある質問を下記にまとめてみたので、参考にしていただけると嬉しいです!

Q1. エンジニアとして向かなかったらどうだろうか? A. 向き不向きは正直あると思いますが、ロジカルシンキングができる人は転職時のストレスが少ないと思います。ただし、ロジカルシンキングは才能というよりも「ロジカルシンキングを求められる環境にいるか」が大事だと思います。今の仕事でロジカルシンキングが必要ないから身についていないだけの場合も多いです。エンジニアとして働けば、嫌でもロジカルシンキングは身についてきます。別の記事で仕事の進め方のテンプレートについて書く予定ですので、その流れで考える練習をすれば、誰でも一定レベルのロジカルシンキングは身につきますので安心してください。

Q2. 収入は上がるのだろうか? A. 上がると思います。ただし、エンジニアとしてどの業態で働くのか、何の言語を選択するのかによって、年収の上がるスピードには差があります。事前にしっかり調べておくことが大切です。業態としては「SES・受託・事業会社」の3つに大きく分けられます。また、言語はJava, Ruby, Pythonなど様々あり、言語によってプロダクトの規模感が変わるため、経験の浅いエンジニアが関わる領域や得られる経験も異なってきます。

Q3. 年齢の上限はありますか? A. 厳密な上限はないと思います。ただし、年齢が上がるにつれて、事前準備の負荷が増えることは確かです。具体的には、自分のスキルをアピールする作品集(ポートフォリオ)をしっかり作りこむことや、企業の面接対策をする必要があります。IT業界は新しい技術がどんどん出てくるため、新しいものを吸収する姿勢やスキルが求められます。年齢が上がると、新しいことの吸収速度が減少する傾向があるため、それを克服できれば理論上は年齢制限はないと言えます。

まとめ

エンジニアとしてのキャリアは、努力次第で誰でも成功できるものです。私自身も未経験から始めて、多くの挑戦を乗り越えながら成長してきました。エンジニアとして働くことで、自分のスキルを日々アップデートし、収入も上がり、働き方の自由度も高まります。興味がある方は、ぜひ一歩を踏み出してみてください。あなたの未来は、あなたの努力次第で無限に広がっています!