8

リクエスト間のデータを保存するためにセッションを使用する eshop やその他のアプリケーションを構築しているかどうかは問題ではありません。ユーザーに登録を要求して迷惑をかけたくない場合は、可能であれば特定のタスクを匿名で実行できるようにする必要があります (ユーザーには登録の理由が必要です)。

問題が発生します。ユーザーが既存のプロファイルでログインすることを決定した場合、「匿名」セッションに既にデータが含まれている可能性があります。

これらのデータをマージするベスト プラクティスは何ですか? アプリケーションは、可能な場合は自動的にマージするか、不可能な場合はユーザーが決定できるようにする必要があると思います。

しかし、私がさらに求めているのは、データベース (通常、セッション データが保存される場所) で魔法を効果的に実行する方法についてのリソースがあるかどうかです。

私は2つの基本的な解決策を考えています:

  1. 匿名のセッション データを保持し、実際に何がどこでどのようにマージされたかを示す別の「関係」を追加するだけです。
  2. これらのデータを物理的にマージするには

関係に関する情報は、おそらくユーザーに関するデータよりも少ないデータを意味するため、最初のソリューションはおそらくより効果的であると言えます。ただし、データを読み取るときの労力も大きくなります (実際のユーザー データを取得するには、最初にリレーションを読み取る必要があるため)。

この特定のユース ケース(匿名 + ユーザー データ) のデータ構造を設計するための記事/リソースはありますか?

4

2 に答える 2

9

ユーザーデータを使用するすべてのアプリ開発者が尋ねるべき素晴らしい質問であり、悲しいことに、ほとんどの人はそうしません:(

実際、ここには 2 つの完全に独立した質問があります。

  • Q1 - ユーザーがサインイン/アップする必要があるのはどの段階ですか?

  • Q2 - データの同時実行性と競合の解決 (以下を参照)。

そして、ここで各質問の分析を行います。私自身の「イライラしたユーザー」の経験から来る私の余分な情熱を許してください. :)


Q1 は純粋なユーザビリティに関する質問です。答えは実際には明白です:

  • ユーザーにサインインを強制することは、できるだけ避けるか遅らせてください。

状態を保存する必要性でさえ、それだけでは十分な理由ではありません。私がユーザーとしてその状態を保存することに興味がない場合は、署名を強制しないでください。お願いします!

あなたが(ウェブサイトとして)私に署名を強制することを正当化する唯一の理由は、私が(ユーザーとして)後で使用するためにデータを保存したいときです. ここで私は、ユーザーが署名に時間を浪費し、サイトが役に立たないことに気付いたとして話します。あまりにも多くのユーザーを取り除きたい場合は、それが正しい方法です。それ以外の場合は、できるだけ遅らせてください。

なぜこれほど多くのサイトが、このような明白なルールを完全に無視するのでしょうか? 私が見ることができる考えられる理由:

  • R1- 開発者向けとユーザー向け。はい、サインインをすぐに要求するのは開発者にとって使いやすいので、同時実行性を気にする必要はありません (Q2)。そのため、開発者のコ​​ストや時間などを節約できます。しかし、すべての節約には代償が伴います! この場合、これはユーザーエクスペリエンスと呼ばれます。これは、必ずしも節約を求めたい場所ではありません。特に、解決策はそれほど難しいものではないはずです(以下を参照)。

  • R2 - 決定を下すデザイナーまたはマネージャーは「インドア エンスージアスト」です :) 彼女は、超高速インターネット接続を備えた超高速コンピューターに囲まれた幸せな生活を送っています。では、なぜそんなに大したことなのですか?非常に多くの理由:

  • アプリケーション フローが中断されます。前世紀に生きていたサイトは、依然として画面全体をかなり長い形式に置き換えています。フォームの中には、デザインが悪いものもあれば、指示が間違っているものもあれば、単に機能しないものもあります。一部のブラウザでは、送信ボタンが何らかの理由で無効になっています。一部のフォーム デザイナーは、特定のフィールドをほとんど目立たない変化や色でロックするという天才的なアイデアを持っています。私に記入させたくないなら、私にそのフィールドを見せないでください!

  • サイトがユーザーのデータを真剣に扱う場合は、電子メールを要求し、それを確認する必要があります! なんで?他のすべての資格情報を忘れたユーザーに戻るには、他にどのようにすればよいですか? なぜ確認するのですか?ユーザーが電子メールを間違って入力した場合はどうなりますか? 確認しないと、次にユーザーが正しい電子メールでパスワードを復元しようとすると、復元に失敗し、すべてのデータが失われます。明らかですが、まだそれを行っていないサイトがあります。次に、確認メールが受信されるまで待って、うまくいけば、適切にフォーマットされた一意に識別可能なリンクをクリックする必要があります。これは、ブラウザで壊れたり、壊れたエンコーディング検出のために変な文字が表示されたりして、リンク全体が使用できなくなったりすることはありません.

  • インターネット接続が遅くなったり壊れたりする可能性があるため、追加の手順を実行するたびに苦痛になります. 接続が良好であっても、ページの読み込みに突然時間がかかることがあちこちで発生します。また、メールがすぐに届かない場合があります。それから、せっかちなユーザーは「再送信検証」リンクを猛烈にクリックし始めます。その場合、サイトの 90% が新しいトークンでリンクを再送信しますが、以前のすべてのトークンも無効にします。次に、いくつかの電子メールが予測できない順序で到着し、貧しいユーザーはどれ (そして 1 つだけ) がまだ有効であるかを推測する必要があります。これらのサイトがいくつかのトークンをアクティブに保つのが非常に難しいと感じる理由は、この場合だけであり、私の理解を超えています.

  • 最後に、サイトがいわゆる「ユーザー名」を主張するのをやめさせるのが非常に難しい習慣がまだあります. だから今、私の電子メールのほかに、以前のどのユーザーとも異なる、このユニークなユーザー名を思いつくために一生懸命考えなければなりません! 甘くて簡単に作ってくれてありがとう!それを処理する私自身の方法は、自分の電子メールをユーザー名として使用することです. 残念ながら、まだ受け付けていないサイトがあります。では、面白いタイプが私のメールをユーザー名として使用していたらどうなるでしょうか? メールアドレスが bill@gates.com であれば、それほど非現実的ではありません。しかし、この混乱を避けるために、単にメールとパスワードを使用しないのはなぜですか?


ユーザーの苦痛を軽減するためのいくつかの可能なガイドラインを次に示します。

  • 絶対に必要な場合にのみ、サインイン/登録を強制し、しないことを選択する機会を与えてください!

  • 1 ページのフォームにして、自分が何をしようとしているのかを把握し、言うまでもなく、できるだけ少ない入力フィールドを使用するようにします。理想的には、メールとパスワードのみ (できれば 2 回) で、ユーザー名はありません!

  • サインイン フォームをリロードせずにページの上部に小さなウィンドウとして表示し、そのウィンドウから 1 回クリックするだけでフォームを削除できるようにします。「閉じる」ボタンや、さらに悪いことに、他の何かと混同する可能性のあるアイコンを探すように強制しないでください。

  • ユーザーが前後にクリックしてボタンをリロードするためのアカウント。リロード時にフォームをクリアしないでください! クリアボタンは絶対につけないで!偶然クリックするのは簡単すぎます。あなたが私に記入を求めているデータは、そもそも「助け」をクリアする必要なしに再入力することができないほど長くすべきではありません.


Q2.質問です。ここでは、2 つのデータをマージする必要がある場合に発生する、よく知られた競合解決の問題があります。たとえば、匿名データと登録済みユーザー データだけでなく、2 人のユーザーが同じデータを変更したり、同じユーザーが異なるデバイスから異なる時間に変更したり、ローカルに保存されたデータがサーバー データと競合したりする場合も同様です。

しかし、ソースが何であれ、問題は常に同じです。たとえば、2 つのオブジェクト $obj1 と $obj2 があり、1 つのマージされたオブジェクト $obj3 を作成する必要があります。ロジックは、サーバーのオブジェクトが常に優先されるルール、最後に変更されたオブジェクトが常に優先されるルール、最後に変更されたオブジェクト キーが常に優先されるルール、またはより複雑なロジックのように単純なものにすることができます。これは、アプリケーションの性質に大きく依存します。しかし、いずれの場合でも、必要なのは、$obj3 を返す引数 $obj1、$obj2 を持つ論理関数を作成することだけです。

多くの場合に有効な解決策は、各オブジェクトの属性 (キー) にタイムスタンプを保存し、同期の時点で最後に変更されたキーが優先されるようにすることです。これは、たとえば、同じユーザーが異なるデバイスから匿名であるときに異なる属性を変更する状況を説明します。

昨日、デバイス AA のキー A と B を変更し、今日デバイス BB からログインして別の B を入力し、それをサーバーに保存してから、匿名のデバイス AA に切り替えて、変更せずにさらに別の A を入力したとします。昨日の古い B で、ログインして同期したいことに気付きました。次に、私のローカル B は明らかに古く、デバイス BB で最近変更した B の値を明らかに上書きすべきではありません。この一見複雑なケースでは、上記のソリューションがシームレスかつ効果的に機能します。対照的に、タイムスタンプをオブジェクト全体にのみ配置するのは間違っています。

場合によっては、両方のオブジェクトを保持することが理にかなっています。たとえば、Radek の質問で提案されているケース 1 のように、追加のプロパティを追加してそれらを区別します。たとえば、Dropbox はファイルの末尾に「ユーザー X による競合コピー」のようなものを追加します。Dropbox の場合と同様に、ユーザーが何らかのバージョン管理を希望するコラボレーション アプリの場合、これは理にかなっています。ただし、そのような場合、開発者は 2 つのコピーを保存して、ユーザーにその問題を処理させます。

一方、ユーザーのデータに基づいて複雑なロジックを作成する必要がある場合、2 つの異なるコピーがぶらぶらしているのは悪夢になる可能性があります。その場合、データを 2 つのグループに分割します (たとえば、1 つのオブジェクトから 2 つのオブジェクトを作成します)。最初のグループには、アプリケーション全体の状態を表すデータがあり、一意であることが重要です。そのデータについては、上記または同様の競合解決を使用します。次に、2 番目のグループはユーザー固有のもので、両方のデータを 2 つの別個のエントリとしてデータベースに保存し、(Dropbox のように) 適切にマークしてから、ユーザーがプロジェクトの 2 つ (またはそれ以上) のエントリのリストを処理できるようにします。 .

最後に、データベース管理の追加の複雑さが開発者を不安にさせている場合、そして Radek がリソース参照を提供するように求めたので、ブログ エントリStackMob offline Syncに言及することで「一発で 2 つのハエを殺す」ことを望みます。そのソリューションはデータベースとデータベースの両方を提供します。ユーザー管理機能を備えているため、開発者はその苦痛から解放されます。確かに、データの同時実行、競合の解決などを検索すると、さらに多くの情報が見つかります。

結論として、義務的な免責事項を追加する必要があります。ここに書かれていることはすべて私自身の考えと提案に過ぎず、誰もが自己責任で使用する必要があり、システムがクラッシュする幸せなユーザーが突然増えすぎても私に責任を負わせないでください。 )

私自身、これらすべての側面を実装しているアプリに取り組んでいるので、他の意見や、このテーマについて他の人々が何を言わなければならないかを聞くことに非常に興味があります.

于 2013-08-26T11:44:06.250 に答える
7

ログインが必要なサイトのユーザーとしても、ログインしているユーザーを扱う開発者としても、私の経験からすると、このようなサイトの動作は見たことがないと思います。

一般的なパターンは、ユーザーを匿名にして、状態の保存が必要な操作を初めて行うときに、ログインを求めることです。その後、以前のアクションが記憶され、ユーザーは続行できます。たとえば、ショッピング カートに何かを追加しようとすると、ログインするように求められ、ログイン後にアイテムがカートに追加されます。

いくつかの場所では、カートをいっぱいにしてからログインできると思います。その時点で、カートは具体的なユーザーに関連付けられます。

サイト インタラクションの状態を持つ SessionUser オブジェクトと、名前や住所などの他の情報を取得するために使用される UserId という 1 つのフィールドを作成します。

匿名ユーザーの場合、UserId の空の参照を使用して SessionUser オブジェクトを作成します。つまり、名前やアドレスを解決することはできませんが、状態を保存することはできます。ユーザーが実行しているアクション、閲覧しているページなど。

ユーザーがログインしたら、2 つのオブジェクトをマージする必要はありません。SessionUser の UserId フィールドに入力するだけで、オブジェクト グラフを走査して、名前、電子メール、アドレスなどを取得できます。

于 2013-08-22T16:17:26.000 に答える