10

JVMの新機能であり、ScalaおよびPlay2.0と連携します

レガシーアプリケーションをPlayに変換しています。これは、Authorize.netによる支払い処理が必要なアプリケーションです。java.net.URLソースを見ると、多くの潜在的な障害点があります。以下に書いたインターフェースを考えると、try / catchブロックをどこに実装しますか?それに応じてメソッドシグネチャを調整する必要があります。おそらく、クライアントコードの呼び出しにEither [Error、Success]を返します。

import java.net.{URL, URLEncoder}
import java.io.{BufferedReader, DataOutputStream, InputStreamReader}
import javax.net.ssl._

trait Authnet {
  private val prodUrl = "https://secure.authorize.net/gateway/transact.dll"
  private val testUrl = "https://test.authorize.net/gateway/transact.dll"

  protected def authNetProcess(params: Map[String,String]) = {
    val(conn, urlParams) = connect(params)
    val request = new DataOutputStream( conn.getOutputStream )
    request.write(urlParams.getBytes)
    request.flush()
    request.close()
    val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
    val results = response.readLine().split("\\|")
    response.close()
    results.toList
  }  

  private def connect(params: Map[String,String]) = {
    val urlParams = (config ++ params) map { case(k,v) =>
        URLEncoder.encode(k, "UTF-8") + "=" + URLEncoder.encode(v, "UTF-8")
    } mkString("&")

    lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
    val conn = url.openConnection
    conn.setDoOutput(true)
    conn.setUseCaches(false)
    (conn, urlParams)
  }

  private val config = Map(
    'x_login        -> "...",
    'x_tran_key     -> "...",
    ...
  )
}
4

2 に答える 2

1

経験則に固執する:

例外を処理する必要がある場合にのみ、例外をキャッチします。

「処理する必要がある」という明確な定義はありませんが、別の例外をスローするだけでよいため、例外をキャッチしたいという衝動に抵抗する必要があることを意味します。

「処理する必要がある」は、主にアプリケーションの動作方法またはその他の依存関係によって定義されます。

アプリケーションが例外で中止するのではなく、ユーザーにエラーを表示する必要がある場合、それは必須です。

その場合、例外をキャッチすると、意味のある処理も追加されます。

APIが別の例外をスローする必要がある場合、それは必須ですが、API定義はおそらく適切ではありません。

私はいつも、例外を別の例外に置き換えることの付加価値に疑問を投げかけています。

これをあなたの例に適用する:

authNetProcess()のconnect()からの例外をキャッチするために、何らかの値を追加しますか?

いいえ!connect()内でその例外を処理する方法はありません。したがって、その例外をauthNetProcessの呼び出し元に任せてもかまいません。そこでは、例外の種類に基づいて異なる処理を提供できます。

于 2012-06-10T10:03:24.047 に答える
0

編集
まあ、接続/ストリームプロセスのいずれかの部分が失敗した場合、トランザクションはホースで処理されるため、接続を開いたときのエラーのみをキャプチャするのはばかげています。トランザクション全体を1つのブロックにラップし、そのcatching (operation) optionままにしておきます。私はあまり心配していません。エラーは一時的なものであるため、エラーの正確な原因(ログに記録されるものは何でも)です。それをキャッチして、ユーザーに再試行してもらいます。エラーが続く場合は、お問い合わせください...

元々 OK、まあ、これまでの賛成票とコメントの欠如を考えると、私が引き出すことができる唯一の結論は...このあたりの誰も彼らが何をしているのか知らない!ふふ、ふふ、冗談;-)

私はJVMを初めて使用しますが、try / catch /finallybloatは急速に古くなっています。Scala型推論の驚異を介して、一般的なエラー処理を簡潔な実装に抽象化しました。
catching ( operation ) option
catching ( operation ) either

他にフィードバックを受け取らない限り、今のところ、接続の作成をキャッチするだけで対処しています(この場合、最も可能性の高いエラー状態だと思います)。新しい実装は次のとおりです。

protected def authNetProcess(params: Map[String,String]) = {
    connect() match {
      case Some(conn) =>
        val request = new DataOutputStream(conn.getOutputStream)
        request.write(getUrlParams(params).getBytes)
        request.flush()
        request.close()
        val response = new BufferedReader(new InputStreamReader(conn.getInputStream))
        val results = response.readLine().split("\\|")
        response.close()
        results.toList
      case None => List[String]()
    }
  }

  private def connect() = {
    lazy val url = if (isDev) new URL(testUrl) else new URL(prodUrl)
    catching ( url.openConnection ) option match {
      case Some(conn) =>
        conn.setDoOutput(true)
        conn.setUseCaches(false)
        //conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
        Some(conn)
      case None => None // connection failed
    }
  }

より厳密なアプローチは、すべての潜在的なエラー条件をmaybeWorked Option操作に抽出し、それらをすべてまとめて理解することだと思います。それはおそらく適切で責任のあるアプローチです...しかし、1日に非常に多くの時間だけ、後でこれを再検討します

フィードバックをいただければ幸いです。

于 2012-06-01T15:51:47.850 に答える