0 フォロワー · 22 投稿

インターシステムズのデータプラットフォームまたはサービスに関連しないものを投稿する場合は、タグを選択します。

質問 Akio Hashimoto · 11月 28, 2024

ここ最近になって、VSCodeで以下のようなエラーが出るようになり、波線だらけになってしまいます。
IRISサーバーとは連携出来ていて、コンパイルも通るので大きな問題ではないのですが、ソースが真っ赤っ赤になってとっても見辛いです。
これらを消す方法があれば教えて下さい。
VSCode、拡張モジュール共に最新です。

Avoid using legacy if/else flow control statements (cachequality:OS0089)

鍋蓋カッコを使わない1行のIF文のところで真っ赤な波線が出まくります。
例:if (a = "") set b = "c"
 

Consider using an If statement instead of a postconditional (cachequality:OS0039)

コマンドの後付条件を記載しているところで、青い波線が出まくります。
例:quit:var=""
 

This QUIT invocation exits the current method; consider using RETURN instead (cachequality:OS0031)

処理の途中で、Quitと書いていることろが黄色い波線が出まくります。

ちなみに、以下のようなメッセージも出ます。

5
1 253
お知らせ Mihoko Iijima · 10月 1, 2024

開発者の皆さん、こんにちは!

USコミュニティで現在開催しているいつもとちょっと違ったコーディングではないイベント:🚶‍♀️InterSystems ウォーキング・チャレンジ🚶‍♂️をご案内します!

(通勤通学でよく歩いている方、賞品Getのチャンスです!)

InterSystemsのウォーキング・チャレンジは、あなたの心を充電し、フィットネスを高めるのに役立ちます。 リューベックからリューネブルクまで、何世紀も前にヨーロッパを結んだ伝説の交易路「塩の道」を歩くバーチャルな旅に出かけましょう。

そして、トレッドミル、スマートウォッチ、メダルなどのエキサイティングな賞品をゲットしましょう!

👟🚶🧑‍🦼Lace Up, Step Out, and Code Better! 🔋💻💪

📅 期間:2024年9月23日~10月20日 11月8日まで(11月22日18時CETにこのチャレンジは終了します)

参加されたい方、以下詳細をご参照ください。

0
0 82
記事 Hiroshi Sato · 9月 12, 2024 1m read

これは InterSystems FAQ サイトの記事です。
 

 以下のようなベンチマーク関連の情報が公開されています。

Intel社と共同で実施したパフォーマンス(レイテンシー)とスケーラビリティ(スループット)を計測するベンチマーク結果

Intel社との共同ベンチマーク

ESG社によるIRISと他社データベースとの性能比較に関するレポート

ESGテクニカルレビュー


ウルシステムズ社が実施したAWS AuroraとIRISの性能評価結果

ウルシステムズ社が検証したベンチマーク結果レポート

オープンソースのベンチマークプログラム

公開しているベンチマークプログラム

WinterCorp社のベンチマークレポート

WInterCorpのベンチマークレポート

様々なハードウェア上で実施したベンチマーク結果を公表

SQLベンチマーク

開発生産性の評価に関連するレポート

Neuralytix社のアプリケーション開発生産性の定量的比較

0
0 112
記事 Yuji Ohata · 9月 8, 2023 6m read

こんにちは、皆さま。
業務でIRISを用いて開発を行っている者です。

技術文書ライティングコンテストという事で、私からはAWS環境を用いたCI/CDの仕組みについてご紹介します。

CI/CDとは「Continuous Integration(継続的インテグレーション)/ Continuous Delivery(継続的デリバリー)」の略称で、
詳細はネットをググると色々出てくると思いますが、私としてはリポジトリに格納されたものを自動で品質保証して、
問題なければ自動でデプロイしてくれる一連の仕組み
だと理解しています。

という事で、その第一歩はIRISのソースコードをgitで管理することです。
pythonで作成したテストプログラムを用意しました。

0
0 507
記事 Toshihiko Minamoto · 12月 12, 2022 16m read

こんにちは! 今日は、Angular で最も重要なアーキテクチャパターンの 1 つについてお話しします。

パターン自体は直接 Angular に関連していませんが、Angular はコンポーネント駆動のフレームワークであるため、このパターンは最新の Angular アプリケーションを構築するために最も不可欠なものの 1 つです。

「コンテナ・プレゼンテーション」パターン

コンポーネントは、小さい、目的集中型、独立型、テスト可能性、そして一番重要と言える再利用可能性という特性が備わっているのが最適だと考えられています。

コンポーネントに、サーバー呼び出しを行う、ビジネスロジックが含まれている、他のコンポーネントと密に連携している、他のコンポーネントまたはサービスの内部を過度に知っている、という特徴が備わっていれば、より大きく、テスト、拡張、再利用、変更が行いにくいものになってしまします。 「コンテナ・プレゼンテーション」パターンは、これらの問題を解決するために存在します。

一般的にすべてのコンポーネントは、コンテナコンポーネント(スマート)とプレゼンテーションコンポーネント(ダム)の 2 つのグループに分けられます。

コンテナコンポーネントは、サービスからデータを取得し(ただし、サーバー API を直接呼び出さない)、何らかのビジネスロジックを含み、サービスまたは子コンポーネントにデータを配信することができます。 通常、コンテナコンポーネントは、ルーティング構成でルートが指定されたコンポーネントとして指定されるものです(もちろん、必ずしもそうとは限りません)。

プレゼンテーションコンポーネントは、入力としてデータを取り、何らかの方法で画面に表示することのみを行います。 これらのコンポーネントはユーザー入力に反応しますが、それはローカルで独立した状態を変更することでのみ発生するものです。 アプリの残りの部分とのすべてのやり取りは、カスタムイベントを発行することで行われます。 これらのコンポーネントには非常に高い再利用可能性が備わっている必要があります。

もう少し分かりやすいように、コンテナコンポーネントとプレゼンテーションコンポーネントの例をいくつか挙げましょう。

コンテナ: About ページ、ユーザーページ、管理者パネル、注文ページなど。

プレゼンテーション: ボタン、カレンダー、テーブル、モーダルダイアログ、テーブルビューなど。

めちゃくちゃなボタンの例

コンポーネントアプローチが誤用されている例として、実際のプロジェクトにおいて私自身が体験した非常に悪い例を見てみましょう。

@Component({
  selector: 'app-button',
  template: `<button class="className" (click)=onClick()>{{label}}</button>`
})
export class ButtonComponent {
  @Input() action = '';
  @Input() className = '';
  @Input() label = '';

  constructor(
    private router: Router,
    private orderService: OrderService,
    private scanService: ScanService,
    private userService: UserService
  ) {}

  onClick() {
    if (this.action === 'registerUser') {
      const userFormData = this.userService.form.value;
      // some validation of user data
      // ...
      this.userService.registerUser(userFormData);
    } else if (this.action === 'scanDocument') {
      this.scanService.scanDocuments();
    } else if (this.action === 'placeOrder') {
      const orderForm = this.orderService.form.values;
      // some validation and business logic related to order form
      // ...
      this.orderService.placeOrder(orderForm);
    } else if (this.action === 'gotoUserAccount') {
      this.router.navigate('user-account');
    } // else if ...
  }
}

読みやすいように単純化してありますが、実際にはもっとひどいものです。 これは、ユーザーがクリックして呼び出せるすべての可能なアクションが含まれたボタンコンポーネントです。API 呼び出し、フォームの検証、サービスからの情報取得などを行います。 このようなコンポーネントは、比較的小さなアプリケーションで使用されていたとしても、あっと言う間に地獄入りしてしまうのが想像できるでしょう。 私が見つけて(後でリファクタリングした)このようなボタンコンポーネントのコードは、2000 行以上にも及ぶものでした。 あり得ません!

それを書いた開発者に、すべてのロジックを 1 つのコンポーネント収めた理由を尋ねたところ、本人が行ったのは「カプセル化」だという答えが返ってきました。🙀

理想的なコンポーネントに備わっているべき特性について思い出しましょう。

小さい - 2000 行以上のコードでできたこのボタンは小さくありません。 また、他のアクション用に別のボタンが必要という人が現れるたびに、コンポーネントが膨れ上がってしまうでしょう。

目的集中型 - このボタンはまったく無関係な多くのアクションを実行するため、目的集中型とは呼べません。

独立型 - このボタンはいくつかのサービスとフォームと密に連携しているため、いずれかを変更すると、ボタンに影響があります。

テスト可能性 - ノーコメントです。

再利用可能性 - まったく再利用できません。 使用するたびに、含まれていないアクションを追加するためにコンポーネントのコードを変更する必要があります。さらに、このボタンの不要なアクションや依存関係もすべて含まれることになります。

さらに、このボタンコンポーネントは、ネイティブの HTML ボタンを内部的に非表示にするため、開発者はそのプロパティにアクセスできません。 これが、コンポーネントの悪い書き方としての良い例です。

このボタンコンポーネントを使用する非常に単純なコンポーネントの例を示し、コンテナ・プレゼンテーションパターンでリファクタリングしてみましょう。

@Component({
  selector: 'app-registration-form',
  template: `<form [formGroup]="userService.form">
  <input type="text" [formControl]="userService.form.get('username')" placeholder="Nickname">
  <input type="password" [formControl]="userService.form.get('password')" placeholder="Password">
  <input type="password" [formControl]="userService.form.get('passwordConfirm')" placeholder="Confirm password">
  <app-button className="button accent" label="Register" action="registerUser"></app-button>
</form>
`
})
export class RegistrationFormComponent {
  constructor(public userService: UserService) {}
}

このコンポーネントの中には何もロジックがありません。フォームはサービスに格納されており、ボタンにはクリックによるすべてのロジックの呼び出しが含まれます。 現時点では、ボタンにその動作に関係のないすべてのロジックが含まれており、ボタンが処理するアクションに直接関係している親コンポーネントよりスマートです。

コンテナ・プレゼンテーションパターンでボタンコンポーネントをリファクタリングする

これらの 2 つのコンポーネントの関数を分離しましょう。 ボタンはプレゼンテーションコンポーネント、つまり小さく再利用可能である必要があります。 このボタンを含む登録フォームは、ビジネスロジックやサーバーレイヤーとのやり取りを保持するコンテナコンポーネントとすることができます。

ネイティブボタンを表示する部分は説明せずに(これについては、おそらく今後の記事で話すことにします)、主に 2 つのコンポーネントのアーキテクチャ上の関係に焦点を当てます。

リファクタリングしたボタンコンポーネント(プレゼンテーション)

@Component({
  selector: 'app-button',
  template: `<button class="className" (click)=onClick()>{{label}}</button>`
})
export class ButtonComponent {
  @Input() className = '';
  @Input() label = '';

  @Output() click: EventEmitter = new EventEmitter();

  onClick() {
     this.click.emit();
  }
}

ご覧のとおり、リファクタリングしたボタンは非常に簡潔です。 2 つの入力と 1 つの出力しか含まれません。 入力は、親コンポーネントからデータを取ってユーザーにそれを表示するために使用します(ボタンの外観はクラスと表示ボタンのラベルで変更します)。 出力は、ユーザーがボタンをクリックするたびに発行されるカスタムイベントに使用されます。

このコンポーネントは小さく、目的集中型、独立型、テスト可能性、および再利用可能性の特性を備えています。 コンポーネント自体の動作に無関係なロジックは含まれていません。 アプリケーションの残りの内部動作についてまったく認識しておらず、アプリケーションのあらゆる部分または他のアプリケーションにも安全にインポートして使用することが可能です。

リファクタリングした登録フォームコンポーネント(コンテナ)

@Component({
  selector: 'app-registration-form',
  template: `<form [formGroup]="userService.form">
  <input type="text" [formControl]="userService.form.get('username')" placeholder="Nickname">
  <input type="password" [formControl]="userService.form.get('password')" placeholder="Password">
  <input type="password" [formControl]="userService.form.get('passwordConfirm')" placeholder="Confirm password">
  <app-button className="button accent" label="Register" (click)="registerUser()"></app-button>
</form>
`
})
export class RegistrationFormComponent {
  constructor(public userService: UserService) {}

  registerUser() {
    const userFormData = this.userService.form.value;
    // some validation of user data
    // ...
    this.userService.registerUser(userFormData);
  }
}

この登録フォームは、ボタンを使用し、ボタンクリックに反応して registerUser メソッドを呼び出すようになりました。 このメソッドのロジックはこのフォームに密に関連しているため、それを配置する最適な場所と言えます。

これは非常に単純な例であり、コンポーネントツリーにあるレベルは 2 つだけです。 このパターンには、コンポーネントツリーのレベルが多い場合に落とし穴があります。

より高度な例

これは実際の例ではありませんが、このパターンに潜在する問題を理解する上で役立つと思います。

以下のようなコンポーネントツリーがあるとします(上から下)。

user-orders - トップレベルのコンポーネント。 サービスレイヤーに話しかけ、ユーザーとその注文に関するデータを受け取り、それを後続のツリーに渡して注文のリストをレンダリングするコンテナコンポーネントです。

user-orders-summary - 中間レベルのコンポーネント ユーザーの注文リストの上に合計注文数を表示するバーをレンダリングするプレゼンテーションコンポーネントです。

cashback - 最下レベル(リーフ/葉)コンポーネント。 ユーザーの合計キャッシュバック額を表示し、銀行口座に引き落とすためのボタンを持つプレゼンテーションコンポーネントです。

トップレベルのコンテナコンポーネント

トップレベルの user-orders コンテナコンポーネントを見てみましょう。

@Component({
  selector: 'user-orders',
  templateUrl: './user-orders.component.html'
})
export class UserOrdersComponent implements OnInit {
  user$: Observable<User>;
  orders$: Observable<Order[]>;

  constructor(
    private ordersService: OrdersService,
    private userService: UserService
  ) {}

  ngOnInit() {
      this.user$ = this.userService.user$;
      this.orders$ = this.ordersService.getUserOrders();
  }

onRequestCashbackWithdrawal() {
    this.ordersService.requestCashbackWithdrawal()
      .subscribe(() => /* notification to user that cashback withdrawal has been requested */);
    }
}
<div class="orders-container">
    <user-orders-summary
        [orders]="orders$ | async"
        [cashbackBalanace]="(user$  | async).cashBackBalance"
        (requestCashbackWithdrawal)="onRequestCashbackWithdrawal($event)"
    >
    </user-orders-summary>

    <div class="orders-list">
      <div class="order" *ngFor="let order of (orders$ | async)"></div>
    </div>
</div>

ご覧のとおり、user-orders コンポーネントは、user$orders$ の 2 つの Obeservable を定義し、非同期パイプをテンプレートに使用してそれらを購読しています。 このコンポーネントはデータをプレゼンテーションコンポーネントの user-orders-summary に渡し、注文リストをレンダリングします。 また、user-orders-summary から発行される requestCashbackWithdrawal カスタムイベントに反応してサービスレイヤーに話しかけます。

中間レベルのプレゼンテーションコンポーネント

@Component({
  selector: 'user-orders-summary',
  template: `
    <div class="total-orders">Total orders: {{orders?.length}}</div>
    <cashback [balance]="cashbackBalanace" (requestCashbackWithdrawal)="onRequestCashbackWithdrawal($event)"></cashback>
    `, 
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserOrdersSummaryComponent {
    @Input() orders: Order[];
    @Input() cashbackBalanace: string;

    @Output() requestCashbackWithdrawal = new EventEmitter();

    onRequestCashbackWithdrawal() {
        this.requestCashbackWithdrawal.emit();
    }
}

このコンポーネントは、上記でリファクタリングしたボタンコンポーネントに非常に似ています。 その入力から受け取ったデータをレンダリングし、何らかのユーザーアクションでカスタムイベントを発行します。 サービスの呼び出しは行わず、ビジネスロジックも含まれません。 そのため、これは別のプレゼンテーション cashback コンポーネントを使用する純粋なプレゼンテーションコンポーネントです。

最下レベルのプレゼンテーションコンポーネント

@Component({
    selector: 'cashback',
    template: `
<div class="cashback">
  <span class="balance">Your cashback balance: {{balance}}</span>
  <button class="button button-primary" (click)="onRequestCashbackWithdrawal()">Withdraw to Bank Account</button>
</div>
`,
    styleUrls: ['./cashback.component.css']
})
export class CashackComponent {
    @Input() balance: string;

    @Output() requestCashbackWithdrawal = new EventEmitter();

    onRequestCashbackWithdrawal() {
        this.requestCashbackWithdrawal.emit();
    }
}

これは、入力からデータを受け取って出力でイベントをスローするだけの、もう 1 つのプレゼンテーションコンポーネントです。 非常に単純で再利用可能ですが、コンポーネントツリーに問題があります

user-orders-summary コンポーネントと cashback コンポーネントには、類似する入力(cashbackBalanacebalance)と同じ出力(requestCashbackWithdrawal)があることに気づいたことでしょう。 これは、コンテナコンポーネントが一番深いプレゼンテーションコンポーネントから遠すぎるためです。 この設計ではツリーのレベル数が増えるほど、問題が悪化してしまいます。 この問題について詳しく見てみましょう。

問題 1 - 中間レベルのプレゼンテーションコンポーネントにある無関係なプロパティ

user-orders-summarycashbackBalanace の入力を受け取って、さらにツリーの下の方に渡すだけであり、それ自体がその入力を使用することはありません。 このような状況に直面した場合、コンポーネントツリーの設計に欠陥がある可能性があります。 実際の状況で使用するコンポーネントには多数の入力と出力があるため、この設計では多数の「プロキシ」入力が含まれてしまい、中間レベルのコンポーネントの再利用可能性が薄れてしまいます(子コンポーネントに密に連携させる必要があるため)。また、繰り返し可能なコードが多数含まれてしまいます。

問題 2 - 下方レベルからトップレベルのコンポーネントに湧き上がるカスタムイベント

この問題は、前の問題に非常に似ていますが、コンポーネントの出力に関連しています。 ご覧のとおり、requestCashbackWithdrawal カスタムイベントは、cashbackuser-orders-summary コンポーネントで繰り返されています。 これもやはり、コンテナコンポーネントが一番深いプレゼンテーションコンポーネントから遠すぎるために起きていることです。 また、中間コンポーネント自体を再利用できないものにしてしまっています。

これらの問題に対する潜在的な解決策は少なくとも 2 つあります。

1 - ngTemplateOutlet を使用して、中間レベルのコンポーネントをよりコンテンツに依存しないコンポーネントにし、より深いコンポーネントをコンテナコンポーネントに直接公開する。 この解決策には専用の記事にするだけの価値があるため、今回はこれについて説明しないでおきます。

2 - コンポーネントツリーを再設計する。

コンポーネントツリーをリファクタリングする

作成したコードをリファクタリングして、無関係なプロパティと中間レベルのコンポーネントで湧いているイベントの問題を解決できるか見てみましょう。

リファクタリングしたトップレベルのコンポーネント

@Component({
  selector: 'user-orders',
  templateUrl: './user-orders.component.html'
})
export class UserOrdersComponent implements OnInit {
  orders$: Observable<Order[]>;

  constructor(
    private ordersService: OrdersService,
  ) {}

  ngOnInit() {
      this.orders$ = this.ordersService.getUserOrders();
  }
}
<div class="orders-container">
    <user-orders-summary [orders]="orders$ | async"></user-orders-summary>

    <div class="orders-list">
      <div class="order" *ngFor="let order of (orders$ | async)"></div>
    </div>
</div>

トップレベルのコンテナコンポーネントから user$ Observable と onRequestCashbackWithdrawal() メソッドを削除しました。 非常に単純化され、user-orders-summary コンポーネント自体をレンダリングするために必要なデータのみを渡し、その子コンポーネントの cashback には渡さないようになっています。

リファクタリングした中間レベルのコンポーネント

@Component({
  selector: 'user-orders-summary',
  template: `
    <div class="total-orders">Total orders: {{orders?.length}}</div>
    <cashback></cashback>
    `, 
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserOrdersSummaryComponent {
    @Input() orders: Order[];
}

これもかなり単純化されています。 入力は 1 つだけで、合計注文数をレンダリングするようになっています。

リファクタリングした最下レベルのコンポーネント

@Component({
    selector: 'cashback',
    template: `
<div class="cashback">
  <span class="balance">Your cashback balance: {{ (user$ | async).cashbackBalance }}</span>
  <button class="button button-primary" (click)="onRequestCashbackWithdrawal()">Withdraw to Bank Account</button>
</div>
`,
    styleUrls: ['./cashback.component.css']
})
export class CashackComponent implements OnInit {
  user$: Observable<User>;

  constructor(
     private ordersService: OrdersService,
     private userService: UserService
  ) {}

  ngOnInit() {
    this.user$ = this.userService.user$;
  }

  onRequestCashbackWithdrawal() {
    this.ordersService.requestCashbackWithdrawal()
      .subscribe(() => /* notification to user that cashback withdrawal has been requested */);
    }
  }
}

すごいです。 ご覧のとおり、プレゼンテーションコンポーネントではなくなっています。 トップレベルのコンポーネントに非常に似ており、コンポーネントツリーの下にあるコンテナコンポーネントになりました。 このようにリファクタリングすることで、コンポーネントツリー全体の設計と API、およびコンポーネントツリーの上位にある 2 つのコンポーネントのロジックを単純化できました。

新しい cashback コンポーネントの再利用可能性についてはどうでしょうか? まだ、再利用可能なままです。それには、コンポーネント自体に関連するロジックのみが含まれているため、以前として独立性を維持しています。

新しいコンポーネントツリーの設計は、管理性、合理性、および細分化がさらに改善されているようです。 湧き上がってくるイベントが無くなり、コンポーネントツリー全体で繰り返し可能な入力もありません。総合的な設計もはるかに単純になっています。 これは、コンポーネントツリーの下にコンテナコンポーネントを追加することで達成しました。 この手法は、コンポーネントツリーの設計を単純化するために使用できますが、再利用可能性を大幅に失うことなく、ツリー内のどのコンポーネントをコンテナにするのが適しており、どれが純粋なプレゼンテーションコンポーネントであるべきかを十分に理解しておくことが必要です。 これはバランスと設計の選択に関する課題であり、アプリのアーキテクチャを作成するときには必ず発生するものです。

「コンテナ・プレゼンテーション」パターンは非常に誤解しやすいもので、コンテナコンポーネントは必ずトップレベルコンポーネントであるべきだと考えがちです(直感的に、コンテナはローカルコンポーネントツリー内のその他すべてのコンポーネントを格納するものです)。 しかし、そうではありません。コンテナコンポーネントはコンポーネントツリーのあらゆるレベルに配置することができます。上記で見たように、リーフレベルにも配置可能です。 私はコンテナコンポーネントをスマート(賢い)コンポーネントと呼んでいます。私にとって、これらのコンポーネントがビジネスロジックを含み、コンポーネントツリーのあらゆる場所に配置できるということが非常に明白であるためです。

後書き

ここまでで、「コンテナ・プレゼンテーション」パターンの概要とその実装における潜在的な問題について理解できたことと思います。

できるだけ単純に維持するよう努めましたが、このパターンに関しては非常に多くの情報が存在します。

ご質問やメッセージがございましたら、お気軽にコメント欄に投稿してください。

次回の記事では、Angular における changeDetectionStrategy についてお話しします(この記事に非常に関連する内容です)。

それではまた!

0
0 764
記事 Toshihiko Minamoto · 11月 29, 2022 11m read

中・上級トピックに進む前に、より一般的なポイントについてまとめておきたいと思います。 これはもちろん主観的な内容であるため、他の意見やさらに良い根拠をお持ちであれば、それについて喜んでお聞きします。

このリストは包括的ではありません。一部のトピックは今後の記事で対応するつもりなので、意図的にそうしています。

ヒント 1. 公式スタイルガイドに従う

Angular は、アプリケーションに使用可能なアーキテクチャを制限するという点で非常に厳格ですが、それでも独自の方法で行えることはたくさんあります。 開発者の想像力は無限ではありますが、そのために、あなたと、またはあなたを引き継いでプロジェクトに携わる人の作業が困難になってしまうことがあります。

Angular チームは、Angular アーキテクチャ自体とそのライブラリをうまく管理しているため、安定した対応可能なコードベースを作成する方法をよく理解しています。

したがって、公式スタイルガイドに従い、そのとおりに動作しない場合にのみ他の方法を取るようにすることをお勧めします。 こうすることで、新しいプロジェクトに参加する際や、他の人がプロジェクトに参加する際に、事がより簡単に進められるようになります。

コードとアプリアーキテクチャが対応可能で安定しており、理解しやすい方が、賢明でありながらも暗号的なソリューションを作るよりも重要です。誰も追いつけなくなってしまいます(開発者自身が後に追いつけなくなる可能性もあります)。

Angular 公式スタイルガイド: https://angular.io/guide/styleguide

ヒント 2. Angular の Ninja 本を購入する

宣伝と思われるかもしれませんが、つまりこういうことです。Angular のすべての主要概念がカバーされた非常に良い本で、価格はあなたが決められます。 また、価格のどれくらいが作者に支払われ、どれくらいが慈善活動に募金されるかを決めることもできます。

この本の作者の 1 人は Angular チームのメンバーであるため、公式ドキュメントの次に最も信頼できる Angular の情報源であることは間違いありません。 本の章構成は、本のページで確認できるようになっているため、サンプルページを読んでから購入する価値があるかを決めることができます。

さらに、この本は Angular の新しいバージョンのリリースで更新されており、本のすべての更新内容を無料で得られます。

Ninja Squad ブログ自体も Angular に関する非常に優れた情報源で、新しいバージョンに関する記事や最新情報、ベストプラクティス、実験的機能などが掲載されています。

Angular の Ninja 本: https://books.ninja-squad.com/angular

ヒント 3. 公式ドキュメントを読む

アプリのコードを書き始める前、特に、以前に使用したことのないバージョンの Angular でプロジェクトに取り組む場合には、公式ドキュメントとガイドに目を通すことをお勧めします。 廃止機能は常に増えており、インターネット上のチュートリアルとガイドが古くなっている可能性があります。そのため、新しいベストプラクティスや機能を使用する代わりに、技術的負債が増え続けてしまうことになりかねません。

ガイドがどのバージョンを対象にして書かれているのかを確認するのも良い習慣です。 使用しているのが 2 つ以上前のバージョンであれば、それが書かれた当時から変更されたことがないかを確認することをお勧めします。

公式ドキュメント: https://angular.io

ヒント 4. Angular Material を使用しなくても、Angular CDK の使用を検討する

これについては今後の記事に取り上げるのが良いと思いますが、私は、多くの Angular 開発者は Angular CDK の存在すらも知らないことを知っています。

Angular CDK は、より優れたアプリケーションの開発を支援できる便利なディレクティブと基底クラスが集められたライブラリです。 たとえば、FocusTrap、Drag & Drop、VirtualScroll などが含まれており、コンポーネントに簡単に追加することができます。

Angular CDK: https://material.angular.io/cdk/categories

ヒント 5. package.json 内の依存関係を修正する

特に Angular に関連することではありませんし、どんなプロジェクトでも重要なことかもしれません。 npm install --save <something> を実行すると、パッケージバージョンの先頭に ^ または ~ 付きで package.json に追加されます。 つまり、プロジェクトはその依存関係と同じメジャーバージョンのあらゆるマイナー/パッチバージョンを使用できるということになります。 この場合、将来的にほぼ 100% の確率で問題となります。 私はさまざまなプロジェクトにおいて何度もこの問題に直面しました。 時間が経過し、ある依存関係の新しいマイナーバージョンが作成されれば、アプリはビルドできなくなります。 この依存関係の作成者がそれをマイナー(またはパッチ)バージョンで更新したために、ビルドと競合するようになってしまうこともあるでしょう。 また、依存関係の新しいマイナーバージョンで新しいバグが見つかることもあります。自分のコードでは問題がなくても(新しいバージョンがリリースされる前に依存関係をインストールしたため)、リポジトリから自分のプロジェクトをインストールしてビルドしようとしている人たちが、自分が気付いていないバグに直面することもあります(また、自分のマシンでそのバグを再現することもできません)。

package-lock.json は、この問題を解決し、複数の開発者がプロジェクト全体で同じ依存関係セットを使用できるようにするために存在します。 リポジトリにコミットすることが理想的ですが、このファイルを .gitignore に追加している開発者がたくさんいます。 それでは意味がなく、結局、上記と同じ問題が起きてしまいます。 そのため、依存関係の解決を盲目的に信頼して特定のバージョンに固定するのではなく、定期的に脆弱性をスキャンして(npm audit を使用)、手動で更新してテストすることをお勧めします。

ヒント 6. できるだけ早期にアプリを新しい Angular バージョンにアップグレードするようにする

Angular は絶えず進化しており、約半年ごとに新しいバージョンがリリースされています。 アプリを最新状態に維持することで、ビルドの高速化やその他の最適化を含むすべての新機能を使用することができます。 この場合には、Angular の次期メジャーバージョンへのアップグレードは大した問題ではないでしょう。 ただし、Angular には、Angular の中間バージョンをスキップしてアプリをアップグレードするためのスケマティックがないため、5 バージョン前の Angular を使用しており、アプリケーションの規模が中~大である場合には、最新バージョンへの更新プロセスが困難になる可能性があります。 各バージョンでアプリケーションが動作することを確認しながら、すべての中間バージョンを 1 つずつアップグレードすることが必要になるでしょう。 Angular CLI のスケマティックを使わずに直接アップデートすることは可能ですが、コツが必要となるため、常にアプリを最新状態に維持しておくことをお勧めします。

ヒント 7. 依存関係リストをできるだけ短くする

新機能が必要となるたびに新しい依存関係をアプリに採り入れるという習慣に陥りやすいものですが、 依存関係ごとに、アプリの複雑性が増し、技術的負債が突然雪崩れてしまうリスクが高まります。

アプリに新しい依存関係を追加すると決めた場合は、以下のことを検討してください。

  • どれほど十分に依存関係がサポートされているか?
  • どれくらいの人が使用しているか?
  • 開発チームはどれくらいの規模か?
  • どれくらい迅速に GitHub 課題をクローズしているか?
  • どれくらい十分に依存関係のドキュメントが書かれているか?
  • Angular の新しいメジャーバージョンがリリースされてからどれくらい迅速に更新されているか?
  • この依存関係によるアプリケーションのパフォーマンスとバンドルサイズへのインパクトはどれくらいか?
  • 将来的に放置または廃止された場合に、この依存関係を入れ替えるのがどれくらい困難になるか?

この質問のいくつかに否定的な回答がある場合、その依存関係を排除するか、少なくとももっと成熟して十分にサポートされているものに交換することを検討してください。

ヒント 8. 「暫定的な」型として <any> を使用しない

繰り返しますが、適切な型を書くには時間がかかるものであり、このスプリントでタスクを完了させる必要があるため、ビジネスロジックを書く際に簡単に any を使いがちです。 もちろん、型は後で追加できますが、 技術的負債がすぐに積もる危険があります。

アプリと型のアーキテクチャは、ビジネスロジックを書く前に定義しておく必要があります。 どのようなオブジェクトがあり、どこで使用されるかを明確に理解しておくかなければなりません。 コードの前に仕様書、ですよね? (Tom Demarco は、この考えが主流になる前にこれについての本を書いています: https://www.amazon.com/Deadline-Novel-About-Project-Management/dp/0932633390

事前に定義された型を使わずにコードを書いている場合、非常に似ているようで異なるオブジェクトを使用する、質の悪いアプリアーキテクチャと関数が出来上がってしまう可能性があります。 そのため、関数ごとに異なる型を作成する(余計に悪くなってしまいます)か、仕様書、型、およびリファクタリングを書くことに時間を費やす必要があるでしょう。後者は、前もってやっていれば時間の無駄になりません。

ヒント 9. ビルドプロセスを理解するのに時間をかける

Angular は、プロジェクトの構築に関する開発者の作業をうまく容易にしていますが、 デフォルトのオプションは、すべての場合に必ずしも最適ではありません。

Angular のビルドプロセスの仕組み、開発ビルドと本番ビルドの違い、Angular で提供されているビルドのオプション(最適化、ソースマップ、バンドル化など)を理解する時間を取りましょう。

ヒント 10. バンドル内のものを調べる

すべてのライブラリがツリーシェイキングを提供しているわけでも、必ずしもすぐにインポートするわけでもありません。そのため、冗長するものがアプリにバンドルされる可能性が必ずあります。

したがって、たまにバンドルの中身を調べる習慣をもつことをお勧めします。

webpack-bundle-analyzer を使ったプロセスをうまく説明した記事がいくつかあるため、ここでは説明しませんが、その中の 1 つのリンクをご覧ください: https://www.digitalocean.com/community/tutorials/angular-angular-webpack-bundle-analyzer

このトピックについては、連載の後の方でより詳しく説明します。

ヒント 11. モジュールにサービスをインポートする代わりに、サービスの providedIn プロパティを使用する

インターネットに公開されている Angular コードサンプルの多くは、モジュールへのサービスのインポートを使用しています。 ただし、Angular 6 または 7 以降では、これはサービスを宣言する方法として推奨されていません。 ツリーシェイキングを有効にし、アプリケーションのバンドル化を改善するには、@Injectable デコレータのプロパティ providedIn を使用する必要があります。 Angular は、どのバンドルにサービスを含める必要があるのか、いつ初期化すべきなのか、サービスのインスタンスをいくつ作成する必要があるのかを理解できるほどスマートなフレームワークです。

providedIn が受け入れる値には 3 つあります。 ほとんどの場合は root で十分ですが、そのほかに 2 つあります。

  • root: サービスアプリケーションの範囲でシングルトンになります。
  • any: すべての Eager ロードされたモジュールにサービスのインスタンスが 1 つ作成され、遅延モジュールごとに別のインスタンスが作成されます。
  • platform: 同じページで実行するすべてのアプリケーションに対し、サービスはシングルトンになります。

ヒント 12. 主要なパフォーマンスルールを忘れないこと

  • 再描画操作と JavaScript 実行を減らすには、コレクションに trackBy を使用する
  • 使用できるすべての場所に onPush 変更検出ストラテジーを使用する(これについては、専用の記事で説明します)
  • 高い処理能力を必要とする計算は、ngZone の外で実行する
  • イベントにスロットル・デバウンスパターンを使用して、不要なサーバー呼び出しとイベントの大量送信を防止する
  • ビッグデータセットの表示には仮想スクロールを使用する
  • テンプレートにデータ変換用の純粋なパイプを使用する
  • AoT コンパイルを使用する
  • アプリケーションの起動には必要ないアプリの部分を遅延読み込みする
  • テンプレートでは計算と条件付き関数呼び出しを使わない(関数呼び出しはイベントのみに使用します)

お読みいただきありがとうございました! いくつかのヒントがお役に立ちますように。 コメントやご意見がございましたら、コメント欄でお知らせください。喜んでお伺いします 😃

それではまた!

0
0 141
記事 Toshihiko Minamoto · 11月 17, 2022 10m read

こんにちは! Sergei Sakisian と申します。InterSystems で 7 年以上、Angular フロントエンドを作成しています。 Angular は非常に人気のあるフレームワークであるため、開発者、お客様、そしてパートナーの皆さんは、アプリケーションのスタックの 1 つとして Angular を選択することがよくあります。

概念、ハウツー、ベストプラクティス、高度なトピックなど、Angular のさまざまな側面を網羅する記事の連載を始めたいと思います。 この連載は、すでに Angular に精通しており、基本概念の説明がいらない方が対象となります。 連載記事のロードマップを作成しているところであるため、まずは、一番新しい Angular リリースの重要な機能をいくつか紹介することから始めることにします。

厳格な型指定のフォーム

これはおそらく、過去 2 年間で最も要望の多かった Angular 機能です。 Angular 14 では、Angular リアクティブフォームを使って、TypeScript のすべての厳格な型チェック機能を使用できるようになりました。

FormControl クラスはジェネリクスになったため、それが保持する値の型を取ることができます。

/* Angular 14 より前*/
const untypedControl = new FormControl(true);
untypedControl.setValue(100); // 値を設定、エラーなし

// 現在
const strictlyTypedControl = new FormControl<boolean>(true);
strictlyTypedControl.setValue(100); // ここで型チェックエラーメッセージが表示されます

// Angular 14
const strictlyTypedControl = new FormControl(true);
strictlyTypedControl.setValue(100); // ここで型チェックエラーメッセージが表示されます

ご覧のとおり、最初の最後の例はほぼ同じですが、結果が異なります。 これは、Angular 14 では、新しい FormControl クラスが、開発者が指定した初期値から型を推論しているためです。 したがって、true が指定された場合、Angular はこの FormControl の型を boolean | null に設定します。 .reset() メソッドには、値が指定されていない場合に値を null にする Nullable 値が必要です。

以前の型なしの FormControl クラスは、UntypedFormControl に変換されています(UntypedFormGroupUntypedFormArray、および UntypedFormBuilder についても同様)が、実質的に FormControl<any> のエイリアスです。 以前のバージョンの Angular からアップグレードしている場合、FormControl クラスのすべてのメンションは、Angular CLI によって UntypedFormControl クラスに置き換えられます。

Untyped* のクラスは、以下のような特定の目的に使用されます。

  1. アプリを、以前のバージョンから移行される前とまったく同じように動作させる(新しい FormControl は、初期値から型を推論することに注意してください)。
  2. すべての FormControl<any> を意図的に使用する。 そのため、すべての UntypedFormControl を手動で FormControl<any> に変更する必要があります。
  3. 開発者にもっと自由度を与える(これについては、後の方で説明します)。

初期値が null である場合、FormControl の型を明示的に指定する必要があることに注意してください。 また、TypeScript には、初期値が false の場合に同じことを行う必要のあるバグが存在します。

フォームの Group については、インターフェースを定義することも可能です。このインターフェースを FormGroup の型として渡すだけです。 この場合、TypeScript は FormGroup 内のすべての型を推論します。

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const login = new FormGroup<LoginForm>({
    email: new FormControl('', {nonNullable: true}),
    password: new FormControl('', {nonNullable: true}),
});

手動で FormGroup を作成した上記の例のように、FormBuilder の .group() メソッドに、事前に定義されたインターフェースを受け入れられるジェネリクス属性が追加されました。

interface LoginForm {
    email: FormControl<string>;
    password?: FormControl<string>;
}

const fb = new FormBuilder();
const login = fb.group<LoginForm>({
    email: '',
    password: '',
});

このインターフェースにはプリミティブな非 nullable 型しかないため、新しい nonNullable FormBuilder プロパティ(NonNullableFormBuilder クラスインスタンスを含み、直接作成することも可能)を使って以下のように単純化できます。

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

❗ 非 nullable 型の FormBuilder を使用する場合、または FormControl に非 nullable 型のオプションを設定する場合、.reset() メソッドを呼び出す際に、リセット値として初期の FormControl 値が使用されることに注意してください。

また、this.form.value のすべてのプロパティがオプションとしてマークされることに注意することも非常に重要です。 以下に例を示します。

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

// login.value
// {
//   email?: string;
//   password?: string;
// }

これは、FormGroup 内のいずれかの FormControl を無効にする際に、この FormControl の値が form.value から削除されるために発生します。

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.value);

// {
//   password: ''
// }

フォームオブジェクト全体を取得するには、.getRawValue() メソッドを使用する必要があります。

const fb = new FormBuilder();
const login = fb.nonNullable.group({
    email: '',
    password: '',
});

login.get('email').disable();
console.log(login.getRawValue());

// {
//   email: '',
//   password: ''
// }

厳格に型付けされたフォームのメリット:

  1. FormControl / FormGroup の値を返すすべてのプロパティとメソッドが厳格に型付けされるようになった。 例: valuegetRawValue()valueChanges
  2. FormControl 値を変更するすべてのメソッドが型安全になった。setValue()patchValue()updateValue()
  3. FormControl が厳格に型付けされた。 このことは、FormGroup の .get() メソッドにも適用されます。 これにより、コンパイル時に存在しない FormControl へのアクセスも防止されます。

新しい FormRecord クラス

新しい FormGroup クラスの欠点は、その動的な性質が失われたことです。 一度定義されると、オンザフライで FormControl を追加または削除することはできません。

この問題を解決するために、Angular は新たに FormRecord クラスを追加しました。 FormRecord は実質的に FormGroup と同じですが、動的であり、そのすべての FormControl に同じ型が使用されます。

folders: new FormRecord({
  home: new FormControl(true, { nonNullable: true }),
  music: new FormControl(false, { nonNullable: true })
});

// グループに新しい FormContol を追加する 
this.foldersForm.get('folders').addControl('videos', new FormControl(false, { nonNullable: true }));

// コントロールの型が異なるため、これにより、コンパイルエラーが発生する
this.foldersForm.get('folders').addControl('books', new FormControl('Some string', { nonNullable: true }));

ご覧のとおり、これには別の制限があります。すべての FormControl は同じ型でなければなりません。 動的と異種の両方を兼ね備えた FormGroup がどうしても必要な場合は、UntypedFormGroup クラスを使用してフォームを定義することをお勧めします。

モジュールレス(スタンドアロン)コンポーネント

これは未だ実験的とされている機能ではありますが、興味深い機能です。 コンポーネント、ディレクティブ、およびパイプをモジュールに含めることなく、これらを定義することができます。

この概念はまだ完全に練られてはいませんが、すでに ngModule を使用せずにアプリケーションをビルドすることができるようになっています。

スタンドアロンコンポーネントを定義するには、Component/Pipe/Directive デコレーターで新しい standalone プロパティを使用する必要があります。

@Component({
  selector: 'app-table',
  standalone: true,
  templateUrl: './table.component.html'
})
export class TableComponent {
}

この場合、このコンポーネントはどの ngModule にも宣言されませんが、 ngModule やその他のスタンドアロンコンポーネントにインポートすることは可能です。

各スタンドアロンコンポーネント/パイプ/ディレクティブには、その依存関係を直接デコレーターにインポートするメカニズムが備えられています。

@Component({
  standalone: true,
  selector: 'photo-gallery',
  // 既存のモジュールは直接スタンドアロンコンポーネントにインポートされる
  // CommonModuleは、*ngIf などの標準の Angular ディレクティブを使用するために直接インポートされる
  // 上記に宣言されるスタンドアロンコンポーネントも直接インポートされる
  imports: [CommonModule, MatButtonModule, TableComponent],
  template: `
    ...
    <button mat-button>Next Page</button>
    <app-table *ngIf="expression"></app-table>
  `,
})
export class PhotoGalleryComponent {
}

前述のとおり、スタンドアロンコンポーネントは、既存の ngModule にインポート可能です。 sharedModule 全体をインポートする必要がなく、本当に必要な物だけをインポートできます。 新しいスタンドアロンコンポーネントを使用し始めるのに適したストラテジーでもあります。

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, HttpClientModule, TableComponent], // import our standalone TableComponent
  bootstrap: [AppComponent]
})
export class AppModule {}

スタンドアロンコンポーネントは、Angular CLI を使って以下を入力すると作成できます。

ng g component --standalone user

モジュールレスアプリケーションをブートストラップ

アプリケーションにあるすべての ngModule を排除する場合は、別の方法でアプリをブートストラップする必要があります。 Angular にはこのための新しい関数があり、それを main.ts ファイルで呼び出す必要があります。

bootstrapApplication(AppComponent);

この関数の 2 つ目のパラメーターを使って、アプリ全体で必要なプロバイダーを定義できます。 通常プロバイダーのほとんどはモジュール内に存在するため、Angular は(現時点では)それに新しい importProvidersFrom 抽出関数を使用する必要があります。

bootstrapApplication(AppComponent, { providers: [importProvidersFrom(HttpClientModule)] });

スタンドアロンコンポーネントの遅延読み込みルート:

Angular には、loadComponent という新しい遅延読み込みルート関数があります。これは、スタンドアロンコンポーネントを読み込むためだけに存在する関数です。

{ 
  path: 'home',
  loadComponent: () => import('./home/home.component').then(m => m.HomeComponent)
}

loadChildren は、ngModule を遅延読み込みできるようにするだけでなく、ルートファイルから直接、子ルートも読み込めるようになっています。

{ 
  path: 'home',
  loadChildren: () => import('./home/home.routes').then(c => c.HomeRoutes)
}

記事の執筆時点におけるいくつかの注意事項

  • スタンドアロンコンポーネント機能は、現在も実験的段階にあります。 将来的に、Webpack の代わりに Vite ビルダーに移行し、ツーリングの改善、ビルド時間の高速化、アプリアーキテクチャの強化、テスト方法の改善などを通じて、機能が大幅に改善されるでしょう。 現時点では、こういったものが多数欠けているため、全パッケージを受け取っていません。いずれにせよ、少なくともこの新しい Angular パラダイムを念頭に、アプリを開発し始めることは可能です。
  • IDE と Angular ツールはまだ、新しいスタンドアロンエンティティを静的に解析する準備を整えていません。 すべての依存関係を各スタンドアロンエンティティにインポートする必要があるため、何かを見逃した場合、コンパイラーもそれを見逃し、ランタイム時に失敗する可能性があります。 これは今後改善されていきますが、現時点ではインポートの際に開発者側の注意が必要です。
  • 現時点では Angular にグローバルインポート機能がないため(Vue などで行われるように)、各スタンドアロンエンティティで、依存関係を確実に 1 つずつインポートする必要があります。 この機能の主な目標は、私が思うところ、ボイラープレートを減らして物事を簡単に実行できるようにすることにあるため、今後のバージョンで解決されることを期待しています。

今日は、これで以上です。 それではまた!

0
0 1049
質問 Akio Hashimoto · 2月 1, 2022

Windows端末でCachéやIRIS等を開発環境として使っています。

Windows11での動作状況について、インターシステムズからの正式な対応はまだのようですので、

下記のバージョンで既にインストールをされている方が居られれば、状況などを教えて頂けないでしょうか。

特に問題無く動いていますでしょうか?

・Caché 2017.1

・IRIS for Health 2019.1

この他のバージョンについても情報が御座いましたらよろしくお願い致します。

2
0 402
記事 Toshihiko Minamoto · 8月 18, 2021 13m read

PHP はその公開当初から、多くのライブラリや市場に出回っているほぼすべてのデータベースとの統合をサポートしていることでよく知られています(またそのことで批判を受けてもいます)。 にもかかわらず、何らかの不可解な理由により、グローバル変数については階層型データベースをサポートしませんでした。

グローバル変数は階層情報を格納するための構造です。 Key-Value型データベースにある程度似ていますが、キーを次のようにマルチレベルにできるという点で異なっています。


Set ^inn("1234567890", "city") = "Moscow"
Set ^inn("1234567890", "city", "street") = "Req Square"
Set ^inn("1234567890", "city", "street", "house") = 1
Set ^inn("1234567890", "year") = 1970
Set ^inn("1234567890", "name", "first") = "Vladimir"
Set ^inn("1234567890", "name", "last") = "Ivanov"

この例では、マルチレベルの情報は、ビルトインのObjectScript言語を使用して、グローバル変数の**^innに保存されています。 グローバル変数^inn**は、ハードドライブに保存されています(これは、最初の「^」記号で示されています)。

PHP からグローバル変数を操作するには、PHP モジュールによって追加される新しい関数が必要となります。これについて、以下で説明します。

グローバル変数は、階層を操作するための多数の関数をサポートしています。固定レベルと縦型のトラバーサルツリーでツリー全体と個別のノードの削除、コピー、および貼り付けを行えます。 また、質の高いデータベースと同様に、ACID トランザクションもサポートされています。 これらは次の2つの理由により、非常に迅速に行われます(一般的なPCで、1秒間に105~106の挿入が行われます)。

  1. グローバル変数は SQL に比べると、より低レベルの抽象化である。
  2. ベースは数十年もの間グローバルスコープで稼働しており、この間に洗練され、コードは完全に最適化されてきた。

グローバル変数について詳しくは、「グローバル変数: データ管理の魔法の剣」という連載記事をご覧ください。

パート1.
ツリー。 パート2.
スパースアレイ。 パート3.

この業界では、グローバル変数は主に、医療、個人データ、銀行などの構造化されていないまばらな情報のストレージシステムで使用されています。

私はPHPを気に入っており、開発作業でも使用しているため、グローバル変数を使って色々と試してみたいと思いました。 IRISとCaché用のPHPモジュールは存在しなかったため、 InterSystemsに問い合わせ、作成するよう依頼しました。 InterSystemsは教育助成金の一環として開発を後援してくれたおかげで、私の院生とともにモジュールを作成することになりました。

一般的に、InterSystems IRISはマルチモデルDBMSであるため、ODBCを通じてSQLを使ってPHPから操作することができますが、私が興味を持っていたのはグローバルであったため、それに使用できるコネクタは存在しなかったのです。

それはさておき、このモジュールはPHP 7.xで利用できます(7.0~7.2でテストしました)。 現在、同じホストにインストールされているInterSystems IRISとCachéでのみ動作します。

OpenExchangeのModuleページ(InterSystems IRISとCachéの開発者向けのプロジェクトとアドオンのディレクトリ)。

開発者同士で関連する体験をシェアできるDISCUSSセクションが設けられています。

こちらからダウンロードしてください。

https://github.com/intersystems-community/php_ext_iris コマンドラインからリポジトリをダウンロードする場合:

git clone https://github.com/intersystems-community/php_ext_iris

 

モジュールのインストール手順(英語・ロシア語)。

モジュールの関数:

<td>
  説明
</td>
<td>
   ノードの値を設定します。iris_set($global, $subscript1, ..., $subscriptN, $value); iris_set($global, $value); 戻り値: true または false(エラーの場合)。この関数のすべてのパラメーターは文字列か数値です。 最初のパラメーターはグローバルの名前で、次にインデックス、そして最後のパラメーターは値です。  iris_set('^time',1); iris_set('^time', 'tree', 1, 1, 'value'); ObjectScript equivalent:   Set ^time = 1 Set ^time("tree", 1, 1) = "value" iris_set($arrayGlobal, $value);パラメーターは2つしかありません。1つ目はグローバルの名前とすべてのインデックスを含む配列で、2つ目は値です。   $node = ['^time', 'tree', 1, 1]; iris_set($node,'value');
</td>
<td>
   ノードの値を取得します。 戻り値: 値(数値または行)、NULL(値が定義されていません)、またはFALSE(エラーの場合)。   iris_get($global, $subscript1, ..., $subscriptN); iris_get($global); この関数のすべてのパラメーターは行または数値です。 1つ目はグローバルの名前で、残りはサブスクリプトです。 グローバルにはサブスクリプトがない場合があります。   $res = iris_get('^time'); $res1 = iris_get('^time', 'tree', 1, 1); iris_get($arrayGlobal); 唯一のパラメーターは、グローバルの名前とそのすべてのサブスクリプトが格納されている配列です。   $node = ['^time', 'tree', 1, 1]; $res = iris_get($node);
</td>
<td>
   ノードの値を削除します。 戻り値: TRUEまたはFALSE(エラーの場合)。   この関数はノードの値のみを削除し、下位のブランチには影響しないことに注意してください。   iris_zkill($global, $subscript1, ..., $subscriptN); iris_zkill($global); この関数のすべてのパラメーターは行または数値です。 1つ目はグローバルの名前で、残りはサブスクリプトです。 グローバルにはサブスクリプトがない場合があります。   $res = iris_zkill('^time'); // 下位ブランチは削除されません。 $res1 = iris_zkill('^time', 'tree', 1, 1); iris_zkill($arrayGlobal); 唯一のパラメーターは、グローバルの名前とそのすべてのサブスクリプトが格納されている配列です。   $a = ['^time', 'tree', 1, 1]; $res = iris_zkill($a);
</td>
<td>
   ノードとすべての子孫ブランチを削除します。 戻り値: TRUEまたはFALSE(エラーの場合)。   iris_kill($global, $subscript1, ..., $subscriptN); iris_kill($global); この関数のすべてのパラメーターは行または数値です。 1つ目はグローバルの名前で、残りはインデックスです。 グローバルにはインデックスがない場合があり、その場合は完全に削除されます。   $res1 = iris_kill('^example', 'subscript1', 'subscript2'); $res = iris_kill('^time'); // グローバルは完全に削除されます。 iris_kill($arrayGlobal); 唯一のパラメーターは、グローバルの名前とそのすべてのサブスクリプトが格納されている配列です。   $a = ['^time', 'tree', 1, 1]; $res = iris_kill($a);
</td>
<td>
   指定されたレベルでグローバルのブランチをトラバースします。戻り値: 同じレベルのグローバルの前のノードのフルネームが格納されている配列、またはFALSE(エラーの場合)。   iris_order($global, $subscript1, ..., $subscriptN); この関数のすべてのパラメーターは文字列または数値です。 1つ目のパラメーターはグローバルの名前で、残りはサブスクリプトです。PHPとObjectScript相当の使用方法: iris_order('^ccc','new2','res2'); // $Order(^ccc("new2", "res2")) iris_order($arrayGlobal); 唯一のパラメーターは、グローバルの名前と最初のノードのサブスクリプトが格納されている配列です。 $node = ['^inn', '1234567890', 'city']; for (; $node !== NULL; $node = iris_order($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } Returns: ^inn, 1234567890, city=Moscow ^inn, 1234567890, year=1970
</td>
<td>
   指定されたレベルでグローバルのブランチを逆順にトラバースします。戻り値: 同じレベルのグローバルの前のノードのフルネームが格納されている配列、またはFALSE(エラーの場合)。   iris_order_rev($global, $subscript1, ..., $subscriptN); この関数のすべてのパラメーターは行または数値です。 1つ目はグローバルの名前で、残りはサブスクリプトです。 PHPとObjectScript相当の使用方法: iris_order_rev('^ccc','new2','res2'); // $Order(^ccc("new2", "res2"), -1) iris_order_rev($arrayGlobal); 唯一のパラメーターは、グローバルの名前と最初のノードのサブスクリプトが格納されている配列です。   $node = ['^inn', '1234567890', 'name', 'last']; for (; $node !== NULL; $node = iris_order_rev($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } 戻り値: ^inn, 1234567890, name, last=Ivanov ^inn, 1234567890, name, first=Vladimir
</td>
<td>
   グローバルの縦型トラバース 戻り値: 下位ノード(使用可能な場合)またはグローバルの次のノード(埋め込みノードがない場合)のフルネームが含まれている配列。   iris_query($global, $subscript1, ..., $subscriptN); この関数のすべてのパラメーターは文字列または数値です。 1つ目はグローバルの名前で、残りはサブスクリプトです。 PHPとObjectScript相当の使用方法: iris_query('^ccc', 'new2', 'res2'); // $Query(^ccc("new2", "res2")) iris_query($arrayGlobal); 唯一のパラメーターは、グローバルの名前と最初のノードのインデックスが格納されている配列です。   $node = ['^inn', 'city']; for (; $node !== NULL; $node = iris_query($node)) { echo join(', ', $node).'='.iris_get($node)."\n"; } 戻り値: ^inn, 1234567890, city=Moscow ^inn, 1234567890, city, street=Req Square ^inn, 1234567890, city, street, house=1 ^inn, 1234567890, name, first=Vladimir ^inn, 1234567890, name, last=Ivanov ^inn, 1234567890, year=1970 この順序は挿入時にグローバル内で自動的に昇順にソートされるため、設定した順序とは異なります。
</td>
<td>
   データベースのディレクトリをセットアップします。戻り値: TRUEまたはFALSE(エラーの場合)。   iris_set_dir('/InterSystems/Cache/mgr'); これはデータベースに接続する前に実行する必要があります。
</td>
<td>
   データベースコマンドを実行します。戻り値: TRUEまたはFALSE(エラーの場合)。 iris_exec('kill ^global(6)'); // グローバルを削除するObjectScriptコマンド
</td>
<td>
  データベースに接続します。
</td>
<td>
  DBとの接続を閉じます。
</td>
<td>
  エラーコードを取得します。
</td>
<td>
  エラーのテキストによる説明を取得します。
</td>
PHP関数
データの操作
iris_set($node, value)
iris_get($node)
iris_zkill($node)
iris_kill($node)
iris_order($node)
iris_order_rev($node)
iris_query($CmdLine)
サービス関数
iris_set_dir($FullPath)
iris_exec($CmdLine)
iris_connect($login, $pass)
iris_quit()
iris_errno()
iris_error()

 

 
モジュールを試してみたい場合は、dockerコンテナーの実装などを確認してください。
 

特にDCや使用したい方のために、Caché用php-moduleがセットアップされた仮想マシンを実行しています。

 
InterSystems Cachéにモジュールを自分でインストールする場合

単なる好奇心で、私のPC(AMD FX-9370@4700Mhz 32GB、LVM、SATA SSD)のdockerコンテナーで新しい値をデータベースに挿入する速度をチェックするプリミティブテストを2つ実行しました。

  • 100万個の新しいノードをグローバルに挿入するのに、1.81秒掛かりました(1秒あたり552Kの挿入)。
  • 同じグローバルの値を1,000,000回更新するのに、1.98秒掛かりました(1秒当たり505Kの更新)。 興味深かったのは、挿入が更新よりも早く行われたということです。 どうやらこれは、迅速な挿入を目的としたデータベースの初期最適化の結果のようです。

明らかに、これらのテストは原始的であり、コンテナー内で実行されるため、100%の正確性または有用性があるとは考えられません。 PCIe SSDにディスクシステムを備えたより強力なハードウェアでは、1秒あたり数千万の挿入を達成可能です。

作成中の機能とその状況

  1. トランザクションを操作するための便利な関数を追加できます(iris_execで使用できます)。
  2. グローバル構造全体を返す関数は実装されていません。PHPからグローバルをトラバースする関数についても同様です。
  3. PHP配列をサブツリーとして保存する関数は実装されていません。
  4. ローカルデータベース変数へのアクセスは実装されていません。 iris_setを使用した方が良いですが、iris_execのみを使用してください。
  5. 逆順での縦型グローバルトラバースは実装されていません。
  6. メソッドを使ったオブジェクト経由のデータベースアクセス(現在の関数に類似)は実装されていません。

現在のモジュールはまだ本番対応とは言えません。高負荷やメモリリークについてのテストは行われていません。 ただし、必要だという方がいらっしゃれば、いつでもご連絡ください(Sergey Kamenev宛: sukamenev@gmail.com)。

結論

グローバルは特定のデータタイプ(医療、個人データなど)に強力で高速な機能を提供しているにも関わらず、長い間、PHPの世界とグローバル変数での階層型データベースの世界では、実質的に重なることがありませんでした。

このモジュールをきっかけに、PHPプログラマーがグローバル変数を試すようになり、ObjectScriptプログラマーがPHPでウェブインターフェースを簡単に開発できるようになることを願っています。

追伸 最後までお読みいただき、ありがとうございました!

0
0 243
記事 Toshihiko Minamoto · 8月 4, 2021 4m read

皆さんこんにちは! よろしければ、ボットが対話できるようになるようお手伝いいただけませんか?

チャットボットはこちらからアクセスしてください: Help my chatbots to talk!

なんだ、そのチャットボットはスマートではないのですか?

このシナリオでは「スマート」は適切な言葉ではありません。 チャットボットはトレーニング済みではありますが、少量のデータでしかトレーニングされていません! ほとんどのチャットボットソリューションでは、機械学習を使用して人間と対話する方法が作成されており、機械学習がうまく機能するには、重要なものが 1 つ必要となります。それはデータです。 

どのように動作しますか?

簡単に説明しましょう。脳があっても人生経験のない人がいるとします。生まれたばかりの赤ん坊です。 この状況では、その人(赤ん坊)は、話している人を見たり、授業を受けたり、映画を見たりなどして、話し方を学習しなければなりません。 この人間の学習プロセスを、機械学習モデルにも当てはめることができます。 機械学習モデルが学習できる状況を与える必要があり、その状況がデータということになります。

** つまり、チャットボットは単なる辞書かオウムということになるのでしょうか…**

全くもってそうではありません。 このアプローチを採用する上での最初の問題は、チャットボットが受け取る各文に対してどのように答えるのかを誰かが教えなければならない、ということです。 この問題に取り組んで、異なる文をいくつ形成できるのかを予測することもできますが、明らかに、この問題を解決する方法ではありません。 この問題を解くための機械学習テクニックはたくさん存在します。特定のデータ量でモデルをトレーニングした後にトレーニングデータの次のトピックでうまく動作するようにするのです。 このために、プログラムはほかの会話のデータを使用して、パターン、単語、同義語、意味を学習します。そしてこのプロセスが機械学習モデルとなるのです。

このチャットボットは一体何を実行できますか?

この時点では、文の意図を予測し、その予測をもとに回答することしかできません。 ボットをトレーニングした後は、その「意識」に以下のような意図しかないと考えてください。

  • 意図: 「こんにちは」、返答: 「やあ!」
  • 意図: 「さようなら」、返答: 「またね!」
  • 意図: 「話しかけないで。」 、返答: 「わかった。」

そして、人間がボットに「ここまで車できましたか?」という文を送信します。 人間にとっては、この文には意図と何ら関係がないことに注意してください。 しかし、おそらくモデルは「意図に関連する可能性」として低い精度でスコア付けを行い、次のように返答するでしょう。

「ここまで車で来ましたか?」という文に対して、私が見つけた最も意義のある意図です。

  • さようなら: 5% の精度
  • こんにちは: 3% の精度

つまり、この相関関係によれば、おそらくチャットボットは「さようなら!」と返答するように決定することでしょう。 しかし、なぜ返答するのでしょうか。 どのように返答すればよいのかがわからないのであれば、黙っている方がよいのではないでしょうか。 おそらく、浅はかな説明をすれば、ボットは考えられる最善の答えで返答すれば、少なくともあなたに関心がないと思われないのではないかと考えたのでしょう。

ボットをトレーニングすれば、作業はそれで終わりですか?

ほとんどの場合、それで終わりではありません。 ボットがうまく動作し始めたとしても、時間が経つごとに精度が失われてしまう確率が十分にあります。 高齢者と若者の話し方の違いを考えてみればわかるように、言語は生ものであり、話し方は常に変化しています。チャットボットについて言えば、新しいデータでトレーニングしたり、新しいテクニックで予測したりする必要があるのです。 つまり、モデルのパフォーマンスを定期的に監視し、新しいデータを使ってモデルを再トレーニングするのが一般的です。 私が今取り組んでいるのはまさにこれです! Help my chatbots to talk!

この記事が役に立った場合、またはコンテンツを気に入った場合は、投票してください。
このアプリケーションは、Open Exchange コンテストに現在参加中です。こちらから私のアプリケーション「iris-python-suite」に投票してください。

0
0 167
記事 Toshihiko Minamoto · 8月 3, 2021 6m read

画像

IRIS と Python でチャットボットを作成する

この記事では、InterSystems IRIS データベースを Python と統合して自然言語処理(NLP)の機械学習モデルを提供する方法を説明します。

Python を使用する理由

世界的に広く採用され使用されている Python には素晴らしいコミュニティがあり、様々なアプリケーションをデプロイするためのアクセラレータ/ライブラリが豊富に提供されています。 関心のある方は https://www.python.org/about/apps/ をご覧ください。

IRIS のグローバル

^globals について学び始めると、型にはまらないデータモデルに素早くデータを取り込む手法として使用することに慣れてきました。 そのため、最初は ^globals を使用してトレーニングデータと会話を保存し、チャットボットの動作をログに記録することにします。

自然言語処理

自然言語処理(NLP)は、人間の言語から意味を読み取って理解する能力を機械に与える AI のテーマです。 ご想像のとおりあまり単純ではありませんが、この広大で魅力的な分野で最初の一歩を踏み出す方法を説明します。

デモ - 試してみましょう

チャットボットアプリケーションをデモとしてデプロイしています: http://iris-python-suite.eastus.cloudapp.azure.com:8080

どのように動作しますか?

機械学習

まず、機械学習には、一般的なソフトウェア開発とは異なるパラダイムがあることを知っておきましょう。 分かりにくい要点は、機械学習モデルの開発サイクルです。

完全な説明ではありません

標準的なアプリケーション開発サイクルは次のようになっています。

コードの開発 -> テスト(開発データを使用)-> デプロイ(実際のデータを使用)

そして、機械学習では、コード自体に同じ価値がありません。 責任はデータと共有されています! つまり、データがなければ、実際のデータもないということです。 これは、実行される最終的なコードは、開発コンセプトと使用されるデータのマージによって生成されるためです。 したがって、機械学習アプリケーションのサイクルは次のようになっています。

モデルの開発(トレーニング)と実データ -> 検証 -> この結果(モデル)をデプロイ

モデルをトレーニングするには

モデルをトレーニングするにはたくさんの手法があり、それぞれのケースと目的には大きな学習曲線が伴います。 ここでは、いくつかの手法をカプセル化して、トレーニング方法と事前処理済みのトレーニングデータを提供する ChatterBot ライブラリを使用し、結果に焦点を当てやすくしています。

事前学習のモデル言語とカスタムモデル

基本的な会話型チャットボットを作成するにはこれを使用することができます。 チャットボットをトレーニングするためのすべてのデータがニーズを完全に満たすように作成することもできますが、短時間で作成するのは困難です。 このプロジェクトでは、会話のベースとして en_core_web_sm を使用し、フォームを使って作成できるカスタムトレーニングデータとマージします。

基本アーキテクチャ

画像

Python で使用したもの

このアプリケーション環境では、Python 3.7 と以下のモジュールを使用します。

  • PyYAML<=5.0.0
  • dash==1.12.0
  • dash-bootstrap-components==0.10.1
  • dash-core-components==1.10.0
  • dash-html-components==1.0.3
  • dash-renderer==1.4.1
  • dash-table==4.7.0
  • plotly==4.7.1
  • numpy==1.18.4
  • networkx==2.4
  • Flask>=1.0.0
  • chatterbot>=1.0.0
  • chatterbot-corpus>=1.2.0
  • SQLAlchemy>=1.2
  • ./nativeAPI_wheel/irisnative-1.0.0-cp34-abi3-linux_x86_64.whl

プロジェクト構造

このプロジェクトは理解しやすい単純な構造になっています。 メインのフォルダには、最も重要な 3 つのサブフォルダがあります。

  • ./app: すべてのアプリケーションコードとインストール構成が含まれます。
  • ./iris: アプリケーションをサービングする InterSystems IRIS dockerfile が含まれます。
  • ./data: ボリュームによってホストをコンテナー環境にリンクします。

アプリケーション構造

./app ディレクトリには、以下のファイルが含まれます。

  • chatbot.py: Web アプリケーションの実装が含まれます。
  • iris_python_suite.py: IRIS Native API によって IRIS データベースや Python と使用する、アクセラレータを持つクラスです。

データベース構造

このアプリケーションでは、InterSystems IRIS をリポジトリとして使用します。使用されるグローバルは以下のとおりです。

  • ^chatbot.training.data: 質疑応答の形式で、すべてのカスタムトレーニングデータを保存します。
  • ^chatbot.conversation: すべての会話ペイロードを保存します。
  • ^chatbot.training.isupdated: トレーニングパイプラインを制御します。

ほかのソリューションの製品

全会話のレポートは作成しませんでしたが、私のグローバルグラフビューアを使用すれば、問題なく会話を追跡することができます。

画像

自分でアプリケーションを実行する

前提条件

  • git
  • docker と docker-compose(docker のメモリ設定を 4 GB 以上に増加してください)
  • 環境のターミナルへのアクセス

手順

docker-compose を使って、すべてのピースと構成を備えた 1 つの環境を簡単に起動できます。iris-python-covid19 フォルダに移動し、次のように入力します。

$ docker compose build
$ docker compose up

コンテナの推定起動時間

初回実行時は、画像や依存関係をダウンロードするためのインターネット接続に依存します。 15 分以上かかる場合は、おそらく何らかの問題が発生しているので、こちらにご連絡ください。 2 回目以降はパフォーマンスが向上し、2 分もかかりません。

すべてが万全である場合

しばらくしたら、ブラウザを開いて次のアドレスに移動します。

トレーニングデータのフォーム

http://localhost:8050/chatbot-training-data

チャットボット

http://localhost:8080

IRIS 管理ポータルの確認

この時点では、USER ネームスペースを使用しています。

http://localhost:9092
user: _SYSTEM
pass: theansweris42

この記事が役に立った場合、またはコンテンツを気に入った場合は、投票してください。

このアプリケーションは、Open Exchange コンテストに現在参加中です。こちら(https://openexchange.intersystems.com/contest/current)から私のアプリケーション「iris-python-suite」に投票してください。

0
0 638
記事 Makiko Kokubun · 4月 13, 2021 1m read

*この動画は、2021年2月に開催された「InterSystems Japan Virtual Summit 2021」のアーカイブです。

インターシステムズでは、昨年7月に日本語版の開発者コミュニティを正式にオープンしました。

この動画では開発者コミュニティの内容や活用方法、アプリケーションやサンプルなどのプログラムを公開するOpen Exchangeの活用方法についてご説明します。また、記事、質問等を投稿することでポイントが得られるグローバルマスターズについてもご説明します。
開発者コミュニティはこちらです。ぜひアクセスしてみてください。
https://jp.community.intersystems.com/

また、開発者コミュニティ内でも使い方や活用方法をご紹介しています。合わせてご覧ください。

0
0 107
ディスカッション Seiji Hirose · 2月 22, 2021

今思えば、製品名に「M」が付いている時代は説明が楽でした。私が記憶している製品は、DTM(Data Tree Mumps:MS-DOS上で巨大なシステムを構築できていましたね)、DSM(Dec Standard Mumps)、MSM(マイクロネティック Standard Mumps あってますか?)、ISM(Intersystems Standard Mumps)、U-MUMPS(?)その他もあったかも知れませんが、M(Mumps)の実装環境です、という説明で何とかなっていました。すると、「へぇ~、MUMPSってまだあったんだね」という答えを頂くこともありました。これらの製品が統合されて「OpenM」となりましたが、まだ「M」の文字が入っており、MUMPSもSQL対応できるようになりました、などと説明していました。

ところが、製品名がCacheになり、趣が大きく変わり、製品の説明が難しくなりました。「データベースです。」→「RDBなの?」→「RDBとしても動作しますがKey-Value的で多次元データ管理もできます」→「OLAP用なの?」→「OLAP処理もできますが、基本はトランザクション処理用です」→「で、結局、何なの」という禅問答のような状況にはまって行きました。

7
0 501
お知らせ Makiko Kokubun · 10月 13, 2020

開発者のみなさん、こんにちは!

インターシステムズは、10/20-11/5 にかけて、年次カンファレンス InterSystems Virtual Summit 2020 をオンラインで開催いたします。

⚡️ 現在、事前登録受付中です! ⚡️

Virtual Summit では、IT技術に詳しい経営層、技術マネージャ、開発者、システムインテグレータの方など、全ての方にとって価値のある内容をお届けします。 今年はすべてのセッションに無料でご参加いただけます!

時間は日本のタイムゾーンに合わせて開催いたします。

今年のサミットのテーマは インタラクション & インフォメーション(相互作用と情報)です。サミットでは、以下のようなセッションが開催されます。

基調講演
適応力の高い組織の創造
10/20 - 10/22

60以上のフォーカスセッション
ベストプラクティス、新機能、ロードマップ 
10/27 - 10/29

ASK THE EXPERTS
専門家と個別にご相談いただけます。
10/30, 11/2

EXPERIENCE LABS
最新技術をハンズオンでご体験いただけます。
11/2 - 11/5

詳細は、こちらをご覧ください。 intersystems.com/summit20

ぜひ、Virtual Summit 2020にご参加ください!

0
0 115
ディスカッション Akio Hashimoto · 9月 3, 2020

前提条件

  • InterSystems ObjectScriptエクステンション 0.9.0
  • Visual Studio Code でローカルにルーチンのファイルを作成している。

問題点

ルーチンをGit等でバージョン管理する等の理由で、IRIS(/Cache)サーバー間でファイル連携している場合に、新規ルーチンをファイルから作成し、サーバーへ「Import and Compile」等を実行するとエラーが出てインポートに失敗する事がある。(xxxxxxxxxxはルーチン名)

ERROR #16006: Document 'xxxxxxxxxx' name is invalid

解決方法

先にサーバーからインポートした事があればお気づきの方もいるかもしれないが、InterSystems ObjectScript エクステンションを使用してルーチンをインポートする場合、ルーチンの先頭行に以下のように1行必要となっている。これが無いと上記のようにエラーとなってしまう。

ROUTINE xxxxxxxxxx

INTやINCファイルの場合は、Type属性が必要。Type属性を省略するとMACファイルとしてインポートされる。

ROUTINE xxxxxxxxxx [Type=INC]

インポートされたサーバー側では上記の1行は追加されたままだが、消してもエクスポートすると自動で付加されるので、一度インポート出来てしまえば心配ない。但し、ローカル側でこの1行を消してしまうと再びエラーとなってしまうので注意して欲しい。

2
0 475
記事 Mihoko Iijima · 4月 28, 2020 9m read

誰もがテスト環境を持っています。  
本番環境とは完全に独立した実行環境を持てるほど幸運な人もいます。  
-- 作者不明 

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Gitフロー(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • GitLab CI/CD 
  • CI/CDとコンテナ 

この最初のパートでは、最新のソフトウェア開発の基礎であるGitバージョン管理システムとさまざまなGitフローを扱います。 

Git 101  

これから説明する主なトピックでは、後の概念をより良く理解できるようにするため、ソフトウェア開発全般とGitlabがその取り込みにどのように役立っているのか、Git、あるいはもっと厳密に言えば重要なGit設計の基礎となる複数の高度な概念を取り上げます。 

そして、Gitは以下のようなアイデア(他にもたくさんありますが、これらが最も重要なアイデアです)に基づいたバージョン管理システムです。 

0
1 493
記事 Mihoko Iijima · 4月 28, 2020 8m read

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Git Flow(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • 継続的デリバリー 
  • GitLabのインストールと構成 
  • GitLab CI/CD 
  • コンテナを使用する理由 
  • コンテナインフラストラクチャ 
  • コンテナを使用するGitLab CI/CD 

第1回の記事では、Gitの基本、Gitの概念を高度に理解することが現代のソフトウェア開発にとって重要である理由、Gitを使用してソフトウェアを開発する方法について説明しています。

第2回の記事では、アイデアからユーザーフィードバックまでの完全なソフトウェアライフサイクルプロセスであるGitLabワークフローについて説明しています。

第3回の記事では、GitLabのインストールと構成ならびに利用環境のGitLabへの接続について説明しています。

第4回の記事では、CDの構成を作成しています。

第5回の記事では、コンテナとその使用方法(および使用する理由)について説明しています。

0
0 809
記事 Mihoko Iijima · 4月 28, 2020 13m read

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Gitフロー(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • 継続的デリバリー 
  • GitLabのインストールと構成 
  • GitLab CI/CD 

第1回の記事では、Gitの基本、Gitの概念を高度に理解することが現代のソフトウェア開発にとって重要である理由、Gitを使用してソフトウェアを開発する方法について説明しました。 

第2回の記事では、アイデアからユーザーフィードバックまでの完全なソフトウェアライフサイクルプロセスであるGitLabワークフローについて説明しました。 

第3回の記事では、GitLabのインストールと構成ならびに利用環境のGitLabへの接続について説明しました。 

この記事では、最終的にCDの構成を作成します。 

計画 

環境 

まず、いくつかの環境とそれに対応するブランチが必要です。

0
0 311
記事 Mihoko Iijima · 4月 28, 2020 6m read

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Gitフロー(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • 継続的デリバリー 
  • GitLabのインストールと構成 
  • GitLab CI/CD 

第1回の記事では、Gitの基本、Gitの概念を高度に理解することが現代のソフトウェア開発にとって重要である理由、Gitを使用してソフトウェアを開発する方法について説明しています。

第2回の記事では、アイデアからユーザーフィードバックまでの完全なソフトウェアライフサイクルプロセスであるGitLabワークフローについて説明しています。 

この記事では以下について説明します。 

  • GitLabのインストールと構成 
  • 利用環境のGitLabへの接続 

GitLabのインストール 

GitLabをオンプレミス環境にインストールします。 GitLabのインストール方法は多彩で、ソースやパッケージからインストールしたり、コンテナーにインストールしたりできます。 ここではすべての手順を実際に説明するつもりはありませんが、そのためのガイドを紹介します。 ただし、それでもいくつか注意すべき点があります。 

前提条件: 

0
0 265
記事 Mihoko Iijima · 4月 28, 2020 7m read

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Gitフロー(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • 継続的デリバリー 
  • GitLabのインストールと構成 
  • GitLab CI/CD 
  • コンテナを使用する理由 
  • コンテナを使用するGitLab CI/CD 

第1回の記事では、Gitの基本、Gitの概念を高度に理解することが現代のソフトウェア開発にとって重要である理由、Gitを使用してソフトウェアを開発する方法について説明していますました。 

第2回の記事では、アイデアからユーザーフィードバックまでの完全なソフトウェアライフサイクルプロセスであるGitLabワークフローについて説明しています。 

第3回の記事では、GitLabのインストールと構成ならびに利用環境のGitLabへの接続について説明しています。 

第4回の記事では、CDの構成を作成しています。 

この記事では、コンテナとその使用方法(および使用する理由)について説明します。 

0
0 228
記事 Mihoko Iijima · 4月 27, 2020 11m read

この連載記事では、InterSystemsの技術とGitLabを使用したソフトウェア開発に向けて実現可能な複数の手法を紹介し、議論したいと思います。 次のようなトピックについて説明します。 

  • Git 101 
  • Gitフロー(開発プロセス) 
  • GitLabのインストール 
  • GitLabワークフロー 
  • 継続的デリバリー 
  • GitLabのインストールと構成 
  • GitLab CI/CD 

前の記事では、Gitの基本、Gitの概念を高度に理解することが現代のソフトウェア開発にとって重要である理由、Gitを使用してソフトウェアを開発する方法について説明しました。 なお、前の記事ではソフトウェア開発の実装部分を中心に取り扱っていましたが、このパートでは以下を取り扱います。 

  • GitLabワークフロー - アイデアからユーザーフィードバックまでの完全なソフトウェアライフサイクルプロセス。 
  • 継続的デリバリー - チームが短いサイクルでソフトウェアを作成し、ソフトウェアをいつでも確実にリリースできるようにするソフトウェアエンジニアリング手法です。 この手法はソフトウェアの構築、テスト、リリースをより速く、より頻繁に行うことを目指しています。 

GitLabワークフロー 

GitLabワークフローは、ソフトウェア開発プロセスのライフサイクル全体で実行可能な操作を論理的に並べたものです。 

0
0 475