Recommended way to deal with delete action in a page?
The way I did it

In my most recent extension with a fair amount of CRUD happening via the UI, I used a different form at a specific URL (civicrm/sms/conversation/confirmdelete) for deleting. This gave the  user the chance to see what they were deleting and confirm it.

I then set the context in preProcess of that form, deleted the entity in postProcess, and let the controller handle redirection.

$this-&gt;context = CRM_Utils_System::url('civicrm/sms/conversation/view', "id={$this-&gt;conversationId}");
$this-&gt;controller-&gt;_destination = $this-&gt;context;
$session-&gt;pushUserContext($this-&gt;context);


IIRC, it was setting $this-&gt;controller-&gt;_destination = $this-&gt;context; that enabled the magic to happen in postProcess, and mean that I didn't have to add any calls to CRM_Utils_System::redirect().

FWIW I generalised this form to allow it to delete any of the entities that my extension was creating.

See the form here: 
https://github.com/3sd/civicrm-sms-conversation/blob/master/CRM/SmsConversation/Form/ConfirmDelete.php

Is this the CiviCRM way?

Since I wasn't sure how 'CiviCRM' this method was, I just had a quick look at how we handle deleting contacts and membership types.

Contacts

For contacts, the URLs look as follows:
civicrm/contact/view/delete?&amp;reset=1&amp;delete=1&amp;cid=2 which maps to CRM_Contact_Form_Task_Delete, i.e. a special form, just for deleting contacts, which (although I haven't looked in details) seems to be a bit like what I did.

Membership types

civicrm/admin/member/membershipType/add?action=delete&amp;id=1 maps to CRM_Member_Form_MembershipType. Looking at the class and its associated template

preProcess sets an appropriate context (this is where you would put your URL to your 'page listing stuff', I think).

$url = CRM_Utils_System::url('civicrm/admin/member/membershipType', 'reset=1');
$session-&gt;pushUserContext($url);


It also assigns the action to the template

$this-&gt;assign('action', $this-&gt;_action);


buildForm checks to see if this is a delete action, and if so, just returns, since it doesn't need to add any form elements

if ($this-&gt;_action &amp; CRM_Core_Action::DELETE) {
  return;
}


postProcess does a similar check

public function postProcess() {
  if ($this-&gt;_action &amp; CRM_Core_Action::DELETE) {
    try {
      CRM_Member_BAO_MembershipType::del($this-&gt;_id);
    }
...


And the template has a similar if else

{if $action eq 8}
  &lt;div class="messages status no-popup"&gt;
    {ts}WARNING: Deleting this option will result in the loss of all membership records of this type.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
  &lt;/div&gt;
  &lt;div&gt; {include file="CRM/common/formButtons.tpl"}&lt;/div&gt;
{else}


So what is the right way?

No comment :) You decide.